This is an automated email from the ASF dual-hosted git repository.

dgrove pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/openwhisk-runtime-dotnet.git


The following commit(s) were added to refs/heads/master by this push:
     new 6ab68a7  Dotnet 3.0 (#20)
6ab68a7 is described below

commit 6ab68a75e3554cc0a2c6f96836b0c3961abcc33f
Author: Shawn Black <shawnalle...@users.noreply.github.com>
AuthorDate: Fri Nov 22 10:52:11 2019 -0600

    Dotnet 3.0 (#20)
    
    * .NET Core 3.0 support
    
    * Updated .NET Core 2.2 project references
       + Updated .NET Core 2.2 Dockerfile to reference latest MS images
       + Migrated Quick Starts to individual projects
       + Moved shared test code to shared folder for reducing duplications
    
    * .NET Core 2.2 quickstart update for JSON reference
    
    * Travis updates Updating to xenial; dotnet sdk 3.0 install
    
    * CHANGELOG Updates
---
 .travis.yml                                        |   4 +-
 README.md                                          | 154 +----------------
 core/dotnet2.2/CHANGELOG.md                        |   2 +-
 core/dotnet2.2/Dockerfile                          |   6 +-
 README.md => core/dotnet2.2/QUICKSTART.md          |  55 +++---
 .../Apache.OpenWhisk.Runtime.Common.csproj         |   2 +-
 .../Apache.OpenWhisk.Runtime.Dotnet.Minimal.csproj |  14 +-
 core/{dotnet2.2 => dotnet3.0}/CHANGELOG.md         |   4 +-
 core/{dotnet2.2 => dotnet3.0}/Dockerfile           |   6 +-
 README.md => core/dotnet3.0/QUICKSTART.md          |  67 +++++---
 .../Nuller.cs => core/dotnet3.0/build.gradle       |  13 +-
 .../Apache.OpenWhisk.Runtime.Common.csproj         |   4 +-
 .../HttpResponseExtension.cs                       |  22 ++-
 .../proxy/Apache.OpenWhisk.Runtime.Common/Init.cs  | 178 +++++++++++++++++++
 .../proxy/Apache.OpenWhisk.Runtime.Common/Run.cs   | 109 ++++++++++++
 .../Apache.OpenWhisk.Runtime.Common/Startup.cs     |  69 ++++++++
 .../Apache.OpenWhisk.Runtime.Dotnet.Minimal.csproj |   5 +-
 .../Program.cs                                     |  26 ++-
 .../Nuller.cs => core/dotnet3.0/proxy/build.gradle |  19 +--
 .../proxy/gradle/wrapper/gradle-wrapper.jar        | Bin 0 -> 54329 bytes
 .../gradle/wrapper/gradle-wrapper.properties}      |  14 +-
 core/dotnet3.0/proxy/gradlew                       | 188 +++++++++++++++++++++
 core/dotnet3.0/proxy/gradlew.bat                   | 100 +++++++++++
 .../dotnet3.0/proxy/openwhisk-runtime-dotnet.sln   |  16 +-
 settings.gradle                                    |   6 +-
 tests/build.gradle                                 |   3 +-
 .../Apache.OpenWhisk.Tests.Dotnet.csproj           |   5 +
 tests/{dotnet => dotnet2.2}/build.gradle           |   2 +-
 .../openwhisk-tests-dotnet.sln                     |   0
 .../Apache.OpenWhisk.Tests.Dotnet.csproj           |   9 +-
 tests/{dotnet => dotnet3.0}/build.gradle           |   7 +-
 .../openwhisk-tests-dotnet.sln                     |  10 +-
 .../AltEcho.cs                                     |   0
 .../Echo.cs                                        |   0
 .../Environment.cs                                 |   0
 .../Error.cs                                       |   9 +-
 .../Exception.cs                                   |   0
 .../NonEmptyConstructor.cs                         |   0
 .../Nuller.cs                                      |   0
 .../Unicode.cs                                     |   0
 ...s.scala => DotNet2_2ActionContainerTests.scala} |   9 +-
 ...s.scala => DotNet3_0ActionContainerTests.scala} |  11 +-
 tools/travis/build.sh                              |   6 +-
 43 files changed, 857 insertions(+), 297 deletions(-)

diff --git a/.travis.yml b/.travis.yml
index c387cf7..bdc9c4a 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -16,7 +16,7 @@
 #
 
 sudo: required
-group: deprecated-2017Q3
+dist: xenial
 language: scala
 scala:
    - 2.12.7
@@ -41,7 +41,7 @@ deploy:
     all_branches: true
     repo: apache/openwhisk-runtime-dotnet
 - provider: script
-  script: "./tools/travis/publish.sh openwhisk 2.2 nightly"
+  script: "./tools/travis/publish.sh openwhisk 2.2 nightly && 
./tools/travis/publish.sh openwhisk 3.0 nightly"
   on:
     branch: master
     repo: apache/openwhisk-runtime-dotnet
diff --git a/README.md b/README.md
index 6e87b8a..a529e1f 100644
--- a/README.md
+++ b/README.md
@@ -23,157 +23,15 @@
 [![Build 
Status](https://travis-ci.org/apache/openwhisk-runtime-dotnet.svg?branch=master)](https://travis-ci.org/apache/openwhisk-runtime-dotnet)
 
 ## Changelogs
-- [.NET Core 2.2 CHANGELOG.md](core/dotnet2.2/CHANGELOG.md)
-
-
-## Quick .NET Core Action
-A .NET Core action is a .NET Core class library with a method called `Main` 
that has the exact signature as follows:
-
-```csharp
-public Newtonsoft.Json.Linq.JObject Main(Newtonsoft.Json.Linq.JObject);
-```
-
-In order to compile, test and archive .NET Core projects, you must have the 
[.NET Core SDK](https://www.microsoft.com/net/download) installed locally and 
the environment variable `DOTNET_HOME` set to the location where the `dotnet` 
executable can be found.
-
-For example, create a C# project called `Apache.OpenWhisk.Example.Dotnet`:
-
-```bash
-dotnet new classlib -n Apache.OpenWhisk.Example.Dotnet -lang C#
-cd Apache.OpenWhisk.Example.Dotnet
-```
-
-Install the [Newtonsoft.Json](https://www.newtonsoft.com/json) NuGet package 
as follows:
-
-```bash
-dotnet add package Newtonsoft.Json -v 12.0.1
-```
-
-Now create a file called `Hello.cs` with the following content:
-
-```csharp
-using System;
-using Newtonsoft.Json.Linq;
-
-namespace Apache.OpenWhisk.Example.Dotnet
-{
-    public class Hello
-    {
-        public JObject Main(JObject args)
-        {
-            string name = "stranger";
-            if (args.ContainsKey("name")) {
-                name = args["name"].ToString();
-            }
-            JObject message = new JObject();
-            message.Add("greeting", new JValue($"Hello, {name}!"));
-            return (message);
-        }
-    }
-}
-```
-
-Publish the project as follows:
-
-```bash
-dotnet publish -c Release -o out
-```
-
-Zip the published files as follows:
 
-```bash
-cd out
-zip -r -0 helloDotNet.bin *
-```
-
-You need to specify the name of the function handler using `--main` argument.
-The value for `main` needs to be in the following format:
-`{Assembly}::{Class Full Name}::{Method}`, e.q.,
-`Apache.OpenWhisk.Example.Dotnet::Apache.OpenWhisk.Example.Dotnet.Hello::Main`
-
-### Create the .NET Core Action
-To use on a deployment of OpenWhisk that contains the runtime as a kind:
-```bash
-wsk action update helloDotNet helloDotNet.bin --main 
Apache.OpenWhisk.Example.Dotnet::Apache.OpenWhisk.Example.Dotnet.Hello::Main 
--kind dotnet:2.2
-```
-
-### Invoke the .NET Core Action
-Action invocation is the same for .NET Core actions as it is for Swift and 
JavaScript actions:
-
-```bash
-wsk action invoke --result helloDotNet --param name World
-```
-
-```json
-  {
-      "greeting": "Hello World!"
-  }
-```
-
-## Local development
-```bash
-./gradlew core:dotnet2.2:distDocker
-```
-This will produce the image `whisk/action-dotnet-v2.2`
-
-Build and Push image
-```bash
-docker login
-./gradlew core:action-dotnet-v2.2:distDocker -PdockerImagePrefix=$prefix-user 
-PdockerRegistry=docker.io
-```
-
-Deploy OpenWhisk using ansible environment that contains the kind `dotnet:2.2`
-Assuming you have OpenWhisk already deploy localy and `OPENWHISK_HOME` 
pointing to root directory of OpenWhisk core repository.
-
-Set `ROOTDIR` to the root directory of this repository.
-
-Redeploy OpenWhisk
-```bash
-cd $OPENWHISK_HOME/ansible
-ANSIBLE_CMD="ansible-playbook -i ${ROOTDIR}/ansible/environments/local"
-$ANSIBLE_CMD setup.yml
-$ANSIBLE_CMD couchdb.yml
-$ANSIBLE_CMD initdb.yml
-$ANSIBLE_CMD wipe.yml
-$ANSIBLE_CMD openwhisk.yml
-```
-
-Or you can use `wskdev` and create a soft link to the target ansible 
environment, for example:
-```
-ln -s ${ROOTDIR}/ansible/environments/local 
${OPENWHISK_HOME}/ansible/environments/local-dotnet
-wskdev fresh -t local-dotnet
-```
-
-### Testing
-Install dependencies from the root directory on $OPENWHISK_HOME repository
-```bash
-pushd $OPENWHISK_HOME
-./gradlew install
-podd $OPENWHISK_HOME
-```
+- [.NET Core 2.2 CHANGELOG.md](core/dotnet2.2/CHANGELOG.md)
+- [.NET Core 3.0 CHANGELOG.md](core/dotnet3.0/CHANGELOG.md)
 
-Using gradle to run all tests
-```bash
-./gradlew :tests:test
-```
-Using gradle to run some tests
-```bash
-./gradlew :tests:test --tests *ActionContainerTests*
-```
-Using IntelliJ:
-- Import project as gradle project.
-- Make sure working directory is root of the project/repo
+## Quick Start Guides
 
-#### Using container image to test
-To use as docker action push to your own dockerhub account
-```bash
-docker tag whisk/action-dotnet-v2.2 $user_prefix/action-dotnet-v2.2
-docker push $user_prefix/action-dotnet-v2.2
-```
-Then create the action using your the image from dockerhub
-```bash
-wsk action update helloDotNet helloDotNet.bin --main 
Apache.OpenWhisk.Example.Dotnet::Apache.OpenWhisk.Example.Dotnet.Hello::Main 
--docker $user_prefix/action-dotnet-v2.2
-```
-The `$user_prefix` is usually your dockerhub user id.
+- [.NET Core 2.2](core/dotnet2.2/QUICKSTART.md)
+- [.NET Core 3.0](core/dotnet3.0/QUICKSTART.md)
 
 # License
+
 [Apache 2.0](LICENSE.txt)
diff --git a/core/dotnet2.2/CHANGELOG.md b/core/dotnet2.2/CHANGELOG.md
index dc50cac..c530536 100644
--- a/core/dotnet2.2/CHANGELOG.md
+++ b/core/dotnet2.2/CHANGELOG.md
@@ -20,6 +20,6 @@
 # .NET Core 2.2 OpenWhisk Runtime Container
 
 
-## 1.13 (next Apache release)
+## 1.13
 Changes:
 - Initial release
diff --git a/core/dotnet2.2/Dockerfile b/core/dotnet2.2/Dockerfile
index 21b9816..70f1067 100644
--- a/core/dotnet2.2/Dockerfile
+++ b/core/dotnet2.2/Dockerfile
@@ -15,7 +15,7 @@
 # limitations under the License.
 #
 
-FROM microsoft/dotnet:2.2-sdk-alpine AS build
+FROM mcr.microsoft.com/dotnet/core/sdk:2.2-alpine AS build
 
 WORKDIR /app
 COPY proxy/Apache.OpenWhisk.Runtime.Common/*.csproj 
./Apache.OpenWhisk.Runtime.Common/
@@ -26,9 +26,9 @@ RUN dotnet restore
 COPY proxy/Apache.OpenWhisk.Runtime.Common/. ./Apache.OpenWhisk.Runtime.Common/
 COPY proxy/Apache.OpenWhisk.Runtime.Dotnet.Minimal/. 
./Apache.OpenWhisk.Runtime.Dotnet.Minimal/
 WORKDIR /app/Apache.OpenWhisk.Runtime.Dotnet.Minimal
-RUN dotnet publish -c Release -r alpine.3.7-x64 -o out
+RUN dotnet publish -c Release -r alpine.3.9-x64 -o out
 
-FROM microsoft/dotnet:2.2-runtime-alpine AS runtime
+FROM mcr.microsoft.com/dotnet/core/runtime:2.2-alpine AS runtime
 WORKDIR /app
 COPY --from=build /app/Apache.OpenWhisk.Runtime.Dotnet.Minimal/out ./
 ENV ASPNETCORE_URLS http://+:8080
diff --git a/README.md b/core/dotnet2.2/QUICKSTART.md
similarity index 84%
copy from README.md
copy to core/dotnet2.2/QUICKSTART.md
index 6e87b8a..7b67b54 100644
--- a/README.md
+++ b/core/dotnet2.2/QUICKSTART.md
@@ -17,16 +17,8 @@
 #
 -->
 
-# Apache OpenWhisk runtimes for .NET Core
+# Quick .NET Core 2.2 Action
 
-[![License](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](http://www.apache.org/licenses/LICENSE-2.0)
-[![Build 
Status](https://travis-ci.org/apache/openwhisk-runtime-dotnet.svg?branch=master)](https://travis-ci.org/apache/openwhisk-runtime-dotnet)
-
-## Changelogs
-- [.NET Core 2.2 CHANGELOG.md](core/dotnet2.2/CHANGELOG.md)
-
-
-## Quick .NET Core Action
 A .NET Core action is a .NET Core class library with a method called `Main` 
that has the exact signature as follows:
 
 ```csharp
@@ -38,14 +30,14 @@ In order to compile, test and archive .NET Core projects, 
you must have the [.NE
 For example, create a C# project called `Apache.OpenWhisk.Example.Dotnet`:
 
 ```bash
-dotnet new classlib -n Apache.OpenWhisk.Example.Dotnet -lang C#
+dotnet new classlib -n Apache.OpenWhisk.Example.Dotnet -lang C# -f 
netstandard2.0
 cd Apache.OpenWhisk.Example.Dotnet
 ```
 
 Install the [Newtonsoft.Json](https://www.newtonsoft.com/json) NuGet package 
as follows:
 
 ```bash
-dotnet add package Newtonsoft.Json -v 12.0.1
+dotnet add package Newtonsoft.Json -v 12.0.2
 ```
 
 Now create a file called `Hello.cs` with the following content:
@@ -82,7 +74,7 @@ Zip the published files as follows:
 
 ```bash
 cd out
-zip -r -0 helloDotNet.bin *
+zip -r -0 helloDotNet.zip *
 ```
 
 You need to specify the name of the function handler using `--main` argument.
@@ -90,13 +82,16 @@ The value for `main` needs to be in the following format:
 `{Assembly}::{Class Full Name}::{Method}`, e.q.,
 `Apache.OpenWhisk.Example.Dotnet::Apache.OpenWhisk.Example.Dotnet.Hello::Main`
 
-### Create the .NET Core Action
+## Create the .NET Core Action
+
 To use on a deployment of OpenWhisk that contains the runtime as a kind:
+
 ```bash
-wsk action update helloDotNet helloDotNet.bin --main 
Apache.OpenWhisk.Example.Dotnet::Apache.OpenWhisk.Example.Dotnet.Hello::Main 
--kind dotnet:2.2
+wsk action update helloDotNet helloDotNet.zip --main 
Apache.OpenWhisk.Example.Dotnet::Apache.OpenWhisk.Example.Dotnet.Hello::Main 
--kind dotnet:2.2
 ```
 
-### Invoke the .NET Core Action
+## Invoke the .NET Core Action
+
 Action invocation is the same for .NET Core actions as it is for Swift and 
JavaScript actions:
 
 ```bash
@@ -109,13 +104,16 @@ wsk action invoke --result helloDotNet --param name World
   }
 ```
 
-## Local development
+## Local Development
+
 ```bash
 ./gradlew core:dotnet2.2:distDocker
 ```
+
 This will produce the image `whisk/action-dotnet-v2.2`
 
 Build and Push image
+
 ```bash
 docker login
 ./gradlew core:action-dotnet-v2.2:distDocker -PdockerImagePrefix=$prefix-user 
-PdockerRegistry=docker.io
@@ -127,6 +125,7 @@ Assuming you have OpenWhisk already deploy localy and 
`OPENWHISK_HOME` pointing
 Set `ROOTDIR` to the root directory of this repository.
 
 Redeploy OpenWhisk
+
 ```bash
 cd $OPENWHISK_HOME/ansible
 ANSIBLE_CMD="ansible-playbook -i ${ROOTDIR}/ansible/environments/local"
@@ -138,13 +137,16 @@ $ANSIBLE_CMD openwhisk.yml
 ```
 
 Or you can use `wskdev` and create a soft link to the target ansible 
environment, for example:
-```
+
+```bash
 ln -s ${ROOTDIR}/ansible/environments/local 
${OPENWHISK_HOME}/ansible/environments/local-dotnet
 wskdev fresh -t local-dotnet
 ```
 
 ### Testing
+
 Install dependencies from the root directory on $OPENWHISK_HOME repository
+
 ```bash
 pushd $OPENWHISK_HOME
 ./gradlew install
@@ -152,28 +154,39 @@ podd $OPENWHISK_HOME
 ```
 
 Using gradle to run all tests
+
 ```bash
 ./gradlew :tests:test
 ```
+
 Using gradle to run some tests
+
 ```bash
-./gradlew :tests:test --tests *ActionContainerTests*
+./gradlew :tests:test --tests DotNet2_2ActionContainerTests
 ```
+
 Using IntelliJ:
+
 - Import project as gradle project.
 - Make sure working directory is root of the project/repo
 
-#### Using container image to test
+#### Using Container Image To Test
+
 To use as docker action push to your own dockerhub account
+
 ```bash
 docker tag whisk/action-dotnet-v2.2 $user_prefix/action-dotnet-v2.2
 docker push $user_prefix/action-dotnet-v2.2
 ```
+
 Then create the action using your the image from dockerhub
+
 ```bash
-wsk action update helloDotNet helloDotNet.bin --main 
Apache.OpenWhisk.Example.Dotnet::Apache.OpenWhisk.Example.Dotnet.Hello::Main 
--docker $user_prefix/action-dotnet-v2.2
+wsk action update helloDotNet helloDotNet.zip --main 
Apache.OpenWhisk.Example.Dotnet::Apache.OpenWhisk.Example.Dotnet.Hello::Main 
--docker $user_prefix/action-dotnet-v2.2
 ```
+
 The `$user_prefix` is usually your dockerhub user id.
 
 # License
-[Apache 2.0](LICENSE.txt)
+
+[Apache 2.0](../../LICENSE.txt)
diff --git 
a/core/dotnet2.2/proxy/Apache.OpenWhisk.Runtime.Common/Apache.OpenWhisk.Runtime.Common.csproj
 
b/core/dotnet2.2/proxy/Apache.OpenWhisk.Runtime.Common/Apache.OpenWhisk.Runtime.Common.csproj
index d667e84..ff84a8d 100644
--- 
a/core/dotnet2.2/proxy/Apache.OpenWhisk.Runtime.Common/Apache.OpenWhisk.Runtime.Common.csproj
+++ 
b/core/dotnet2.2/proxy/Apache.OpenWhisk.Runtime.Common/Apache.OpenWhisk.Runtime.Common.csproj
@@ -28,7 +28,7 @@
         <Version>2.2.0</Version>
       </PackageReference>
       <PackageReference Include="Newtonsoft.Json">
-        <Version>12.0.1</Version>
+        <Version>12.0.2</Version>
       </PackageReference>
     </ItemGroup>
 
diff --git 
a/core/dotnet2.2/proxy/Apache.OpenWhisk.Runtime.Dotnet.Minimal/Apache.OpenWhisk.Runtime.Dotnet.Minimal.csproj
 
b/core/dotnet2.2/proxy/Apache.OpenWhisk.Runtime.Dotnet.Minimal/Apache.OpenWhisk.Runtime.Dotnet.Minimal.csproj
index ce08efe..2d3a42a 100644
--- 
a/core/dotnet2.2/proxy/Apache.OpenWhisk.Runtime.Dotnet.Minimal/Apache.OpenWhisk.Runtime.Dotnet.Minimal.csproj
+++ 
b/core/dotnet2.2/proxy/Apache.OpenWhisk.Runtime.Dotnet.Minimal/Apache.OpenWhisk.Runtime.Dotnet.Minimal.csproj
@@ -22,19 +22,7 @@
     </PropertyGroup>
 
     <ItemGroup>
-      <PackageReference Include="Microsoft.AspNetCore">
-        <Version>2.2.0</Version>
-      </PackageReference>
-      <PackageReference Include="Microsoft.AspNetCore.Server.Kestrel">
-        <Version>2.2.0</Version>
-      </PackageReference>
-      <PackageReference Include="Newtonsoft.Json">
-        <Version>12.0.1</Version>
-      </PackageReference>
-    </ItemGroup>
-
-    <ItemGroup>
       <ProjectReference 
Include="..\Apache.OpenWhisk.Runtime.Common\Apache.OpenWhisk.Runtime.Common.csproj"
 />
     </ItemGroup>
-
+    
 </Project>
diff --git a/core/dotnet2.2/CHANGELOG.md b/core/dotnet3.0/CHANGELOG.md
similarity index 91%
copy from core/dotnet2.2/CHANGELOG.md
copy to core/dotnet3.0/CHANGELOG.md
index dc50cac..9339dd7 100644
--- a/core/dotnet2.2/CHANGELOG.md
+++ b/core/dotnet3.0/CHANGELOG.md
@@ -17,9 +17,9 @@
 #
 -->
 
-# .NET Core 2.2 OpenWhisk Runtime Container
+# .NET Core 3.0 OpenWhisk Runtime Container
 
 
-## 1.13 (next Apache release)
+## 1.14 (next Apache release)
 Changes:
 - Initial release
diff --git a/core/dotnet2.2/Dockerfile b/core/dotnet3.0/Dockerfile
similarity index 89%
copy from core/dotnet2.2/Dockerfile
copy to core/dotnet3.0/Dockerfile
index 21b9816..9e9576f 100644
--- a/core/dotnet2.2/Dockerfile
+++ b/core/dotnet3.0/Dockerfile
@@ -15,7 +15,7 @@
 # limitations under the License.
 #
 
-FROM microsoft/dotnet:2.2-sdk-alpine AS build
+FROM mcr.microsoft.com/dotnet/core/sdk:3.0-alpine AS build
 
 WORKDIR /app
 COPY proxy/Apache.OpenWhisk.Runtime.Common/*.csproj 
./Apache.OpenWhisk.Runtime.Common/
@@ -26,9 +26,9 @@ RUN dotnet restore
 COPY proxy/Apache.OpenWhisk.Runtime.Common/. ./Apache.OpenWhisk.Runtime.Common/
 COPY proxy/Apache.OpenWhisk.Runtime.Dotnet.Minimal/. 
./Apache.OpenWhisk.Runtime.Dotnet.Minimal/
 WORKDIR /app/Apache.OpenWhisk.Runtime.Dotnet.Minimal
-RUN dotnet publish -c Release -r alpine.3.7-x64 -o out
+RUN dotnet publish -c Release -r alpine.3.9-x64 -o out
 
-FROM microsoft/dotnet:2.2-runtime-alpine AS runtime
+FROM mcr.microsoft.com/dotnet/core/runtime:3.0-alpine AS runtime
 WORKDIR /app
 COPY --from=build /app/Apache.OpenWhisk.Runtime.Dotnet.Minimal/out ./
 ENV ASPNETCORE_URLS http://+:8080
diff --git a/README.md b/core/dotnet3.0/QUICKSTART.md
similarity index 77%
copy from README.md
copy to core/dotnet3.0/QUICKSTART.md
index 6e87b8a..c8e720f 100644
--- a/README.md
+++ b/core/dotnet3.0/QUICKSTART.md
@@ -17,16 +17,8 @@
 #
 -->
 
-# Apache OpenWhisk runtimes for .NET Core
+# Quick .NET Core 3.0 Action
 
-[![License](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](http://www.apache.org/licenses/LICENSE-2.0)
-[![Build 
Status](https://travis-ci.org/apache/openwhisk-runtime-dotnet.svg?branch=master)](https://travis-ci.org/apache/openwhisk-runtime-dotnet)
-
-## Changelogs
-- [.NET Core 2.2 CHANGELOG.md](core/dotnet2.2/CHANGELOG.md)
-
-
-## Quick .NET Core Action
 A .NET Core action is a .NET Core class library with a method called `Main` 
that has the exact signature as follows:
 
 ```csharp
@@ -38,14 +30,14 @@ In order to compile, test and archive .NET Core projects, 
you must have the [.NE
 For example, create a C# project called `Apache.OpenWhisk.Example.Dotnet`:
 
 ```bash
-dotnet new classlib -n Apache.OpenWhisk.Example.Dotnet -lang C#
+dotnet new classlib -n Apache.OpenWhisk.Example.Dotnet -lang C# -f 
netstandard2.1
 cd Apache.OpenWhisk.Example.Dotnet
 ```
 
 Install the [Newtonsoft.Json](https://www.newtonsoft.com/json) NuGet package 
as follows:
 
 ```bash
-dotnet add package Newtonsoft.Json -v 12.0.1
+dotnet add package Newtonsoft.Json -v 12.0.2
 ```
 
 Now create a file called `Hello.cs` with the following content:
@@ -82,7 +74,7 @@ Zip the published files as follows:
 
 ```bash
 cd out
-zip -r -0 helloDotNet.bin *
+zip -r -0 helloDotNet.zip *
 ```
 
 You need to specify the name of the function handler using `--main` argument.
@@ -90,13 +82,16 @@ The value for `main` needs to be in the following format:
 `{Assembly}::{Class Full Name}::{Method}`, e.q.,
 `Apache.OpenWhisk.Example.Dotnet::Apache.OpenWhisk.Example.Dotnet.Hello::Main`
 
-### Create the .NET Core Action
+## Create the .NET Core Action
+
 To use on a deployment of OpenWhisk that contains the runtime as a kind:
+
 ```bash
-wsk action update helloDotNet helloDotNet.bin --main 
Apache.OpenWhisk.Example.Dotnet::Apache.OpenWhisk.Example.Dotnet.Hello::Main 
--kind dotnet:2.2
+wsk action update helloDotNet helloDotNet.zip --main 
Apache.OpenWhisk.Example.Dotnet::Apache.OpenWhisk.Example.Dotnet.Hello::Main 
--kind dotnet:3.0
 ```
 
-### Invoke the .NET Core Action
+## Invoke the .NET Core Action
+
 Action invocation is the same for .NET Core actions as it is for Swift and 
JavaScript actions:
 
 ```bash
@@ -109,24 +104,28 @@ wsk action invoke --result helloDotNet --param name World
   }
 ```
 
-## Local development
+## Local Development
+
 ```bash
-./gradlew core:dotnet2.2:distDocker
+./gradlew core:dotnet3.0:distDocker
 ```
-This will produce the image `whisk/action-dotnet-v2.2`
+
+This will produce the image `whisk/action-dotnet-v3.0`
 
 Build and Push image
+
 ```bash
 docker login
-./gradlew core:action-dotnet-v2.2:distDocker -PdockerImagePrefix=$prefix-user 
-PdockerRegistry=docker.io
+./gradlew core:action-dotnet-v3.0:distDocker -PdockerImagePrefix=$prefix-user 
-PdockerRegistry=docker.io
 ```
 
-Deploy OpenWhisk using ansible environment that contains the kind `dotnet:2.2`
+Deploy OpenWhisk using ansible environment that contains the kind `dotnet:3.0`
 Assuming you have OpenWhisk already deploy localy and `OPENWHISK_HOME` 
pointing to root directory of OpenWhisk core repository.
 
 Set `ROOTDIR` to the root directory of this repository.
 
 Redeploy OpenWhisk
+
 ```bash
 cd $OPENWHISK_HOME/ansible
 ANSIBLE_CMD="ansible-playbook -i ${ROOTDIR}/ansible/environments/local"
@@ -138,13 +137,16 @@ $ANSIBLE_CMD openwhisk.yml
 ```
 
 Or you can use `wskdev` and create a soft link to the target ansible 
environment, for example:
-```
+
+```bash
 ln -s ${ROOTDIR}/ansible/environments/local 
${OPENWHISK_HOME}/ansible/environments/local-dotnet
 wskdev fresh -t local-dotnet
 ```
 
 ### Testing
+
 Install dependencies from the root directory on $OPENWHISK_HOME repository
+
 ```bash
 pushd $OPENWHISK_HOME
 ./gradlew install
@@ -152,28 +154,39 @@ podd $OPENWHISK_HOME
 ```
 
 Using gradle to run all tests
+
 ```bash
 ./gradlew :tests:test
 ```
+
 Using gradle to run some tests
+
 ```bash
-./gradlew :tests:test --tests *ActionContainerTests*
+./gradlew :tests:test --tests DotNet3_0ActionContainerTests
 ```
+
 Using IntelliJ:
+
 - Import project as gradle project.
 - Make sure working directory is root of the project/repo
 
-#### Using container image to test
+#### Using Container Image To Test
+
 To use as docker action push to your own dockerhub account
+
 ```bash
-docker tag whisk/action-dotnet-v2.2 $user_prefix/action-dotnet-v2.2
-docker push $user_prefix/action-dotnet-v2.2
+docker tag whisk/action-dotnet-v3.0 $user_prefix/action-dotnet-v3.0
+docker push $user_prefix/action-dotnet-v3.0
 ```
+
 Then create the action using your the image from dockerhub
+
 ```bash
-wsk action update helloDotNet helloDotNet.bin --main 
Apache.OpenWhisk.Example.Dotnet::Apache.OpenWhisk.Example.Dotnet.Hello::Main 
--docker $user_prefix/action-dotnet-v2.2
+wsk action update helloDotNet helloDotNet.zip --main 
Apache.OpenWhisk.Example.Dotnet::Apache.OpenWhisk.Example.Dotnet.Hello::Main 
--docker $user_prefix/action-dotnet-v3.0
 ```
+
 The `$user_prefix` is usually your dockerhub user id.
 
 # License
-[Apache 2.0](LICENSE.txt)
+
+[Apache 2.0](../../LICENSE.txt)
diff --git a/tests/dotnet/Apache.OpenWhisk.Tests.Dotnet/Nuller.cs 
b/core/dotnet3.0/build.gradle
similarity index 80%
copy from tests/dotnet/Apache.OpenWhisk.Tests.Dotnet/Nuller.cs
copy to core/dotnet3.0/build.gradle
index 6769f67..3d62aac 100644
--- a/tests/dotnet/Apache.OpenWhisk.Tests.Dotnet/Nuller.cs
+++ b/core/dotnet3.0/build.gradle
@@ -15,15 +15,6 @@
  * limitations under the License.
  */
 
-using Newtonsoft.Json.Linq;
+ext.dockerImageName = 'action-dotnet-v3.0'
 
-namespace Apache.OpenWhisk.Tests.Dotnet
-{
-    public class Nuller
-    {
-        public JObject Main(JObject args)
-        {
-            return (null);
-        }
-    }
-}
+apply from: '../../gradle/docker.gradle'
diff --git 
a/core/dotnet2.2/proxy/Apache.OpenWhisk.Runtime.Common/Apache.OpenWhisk.Runtime.Common.csproj
 
b/core/dotnet3.0/proxy/Apache.OpenWhisk.Runtime.Common/Apache.OpenWhisk.Runtime.Common.csproj
similarity index 93%
copy from 
core/dotnet2.2/proxy/Apache.OpenWhisk.Runtime.Common/Apache.OpenWhisk.Runtime.Common.csproj
copy to 
core/dotnet3.0/proxy/Apache.OpenWhisk.Runtime.Common/Apache.OpenWhisk.Runtime.Common.csproj
index d667e84..db2338b 100644
--- 
a/core/dotnet2.2/proxy/Apache.OpenWhisk.Runtime.Common/Apache.OpenWhisk.Runtime.Common.csproj
+++ 
b/core/dotnet3.0/proxy/Apache.OpenWhisk.Runtime.Common/Apache.OpenWhisk.Runtime.Common.csproj
@@ -17,7 +17,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
     <PropertyGroup>
-        <TargetFramework>netcoreapp2.2</TargetFramework>
+        <TargetFramework>netcoreapp3.0</TargetFramework>
     </PropertyGroup>
 
     <ItemGroup>
@@ -28,7 +28,7 @@
         <Version>2.2.0</Version>
       </PackageReference>
       <PackageReference Include="Newtonsoft.Json">
-        <Version>12.0.1</Version>
+        <Version>12.0.2</Version>
       </PackageReference>
     </ItemGroup>
 
diff --git a/tests/dotnet/Apache.OpenWhisk.Tests.Dotnet/NonEmptyConstructor.cs 
b/core/dotnet3.0/proxy/Apache.OpenWhisk.Runtime.Common/HttpResponseExtension.cs
similarity index 54%
copy from tests/dotnet/Apache.OpenWhisk.Tests.Dotnet/NonEmptyConstructor.cs
copy to 
core/dotnet3.0/proxy/Apache.OpenWhisk.Runtime.Common/HttpResponseExtension.cs
index f7ecc66..4f63bd0 100644
--- a/tests/dotnet/Apache.OpenWhisk.Tests.Dotnet/NonEmptyConstructor.cs
+++ 
b/core/dotnet3.0/proxy/Apache.OpenWhisk.Runtime.Common/HttpResponseExtension.cs
@@ -15,19 +15,29 @@
  * limitations under the License.
  */
 
+using System.Text;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Http;
+using Newtonsoft.Json;
 using Newtonsoft.Json.Linq;
 
-namespace Apache.OpenWhisk.Tests.Dotnet
+namespace Apache.OpenWhisk.Runtime.Common
 {
-    public class NonEmptyConstructor
+    public static class HttpResponseExtension
     {
-        public NonEmptyConstructor(string value)
+        public static async Task WriteResponse(this HttpResponse response, int 
code, string content)
         {
-            System.Console.WriteLine(value);
+            byte[] bytes = Encoding.UTF8.GetBytes(content);
+            response.ContentLength = bytes.Length;
+            response.StatusCode = code;
+            await response.WriteAsync(content);
         }
-        public JObject Main(JObject args)
+
+        public static async Task WriteError(this HttpResponse response, string 
errorMessage)
         {
-            return (args);
+            JObject message = new JObject {{"error", new 
JValue(errorMessage)}};
+            await WriteResponse(response, 502, 
JsonConvert.SerializeObject(message));
         }
+
     }
 }
diff --git a/core/dotnet3.0/proxy/Apache.OpenWhisk.Runtime.Common/Init.cs 
b/core/dotnet3.0/proxy/Apache.OpenWhisk.Runtime.Common/Init.cs
new file mode 100644
index 0000000..f5d9489
--- /dev/null
+++ b/core/dotnet3.0/proxy/Apache.OpenWhisk.Runtime.Common/Init.cs
@@ -0,0 +1,178 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+using System;
+using System.IO;
+using System.Reflection;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Http;
+using Newtonsoft.Json.Linq;
+
+namespace Apache.OpenWhisk.Runtime.Common
+{
+    public class Init
+    {
+        private readonly SemaphoreSlim _initSemaphoreSlim = new 
SemaphoreSlim(1, 1);
+
+        public bool Initialized { get; private set; }
+        private Type Type { get; set; }
+        private MethodInfo Method { get; set; }
+        private ConstructorInfo Constructor { get; set; }
+
+        public Init()
+        {
+            Initialized = false;
+            Type = null;
+            Method = null;
+            Constructor = null;
+        }
+
+        public async Task<Run> HandleRequest(HttpContext httpContext)
+        {
+            await _initSemaphoreSlim.WaitAsync();
+            try
+            {
+                if (Initialized)
+                {
+                    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));
+                }
+
+                string body = await new 
StreamReader(httpContext.Request.Body).ReadToEndAsync();
+                JObject inputObject = JObject.Parse(body);
+                if (!inputObject.ContainsKey("value"))
+                {
+                    await httpContext.Response.WriteError("Missing main/no 
code to execute.");
+                    return (null);
+                }
+
+                JToken message = inputObject["value"];
+
+                if (message["main"] == null || message["binary"] == null || 
message["code"] == null)
+                {
+                    await httpContext.Response.WriteError("Missing main/no 
code to execute.");
+                    return (null);
+                }
+
+                string main = message["main"].ToString();
+
+                bool binary = message["binary"].ToObject<bool>();
+
+                if (!binary)
+                {
+                    await httpContext.Response.WriteError("code must be binary 
(zip file).");
+                    return (null);
+                }
+
+                string[] mainParts = main.Split("::");
+                if (mainParts.Length != 3)
+                {
+                    await httpContext.Response.WriteError("main required 
format is \"Assembly::Type::Function\".");
+                    return (null);
+                }
+
+                string base64Zip = message["code"].ToString();
+                string tempPath = Path.Combine(Environment.CurrentDirectory, 
Guid.NewGuid().ToString());
+                string tempFile = Path.GetTempFileName();
+                await File.WriteAllBytesAsync(tempFile, 
Convert.FromBase64String(base64Zip));
+                try
+                {
+                    System.IO.Compression.ZipFile.ExtractToDirectory(tempFile, 
tempPath);
+                }
+                catch (Exception)
+                {
+                    await httpContext.Response.WriteError("Unable to 
decompress package.");
+                    return (null);
+                }
+                finally
+                {
+                    File.Delete(tempFile);
+                }
+
+                Environment.CurrentDirectory = tempPath;
+
+                string assemblyFile = $"{mainParts[0]}.dll";
+
+                string assemblyPath = Path.Combine(tempPath, assemblyFile);
+
+                if (!File.Exists(assemblyPath))
+                {
+                    await httpContext.Response.WriteError($"Unable to locate 
requested assembly (\"{assemblyFile}\").");
+                    return (null);
+                }
+
+                try
+                {
+                    Assembly assembly = Assembly.LoadFrom(assemblyPath);
+                    Type = assembly.GetType(mainParts[1]);
+                    if (Type == null)
+                    {
+                        await httpContext.Response.WriteError($"Unable to 
locate requested type (\"{mainParts[1]}\").");
+                        return (null);
+                    }
+                    Method = Type.GetMethod(mainParts[2]);
+                    Constructor = Type.GetConstructor(Type.EmptyTypes);
+                }
+                catch (Exception ex)
+                {
+                    Console.Error.WriteLine(ex.ToString());
+                    await httpContext.Response.WriteError(ex.Message
+#if DEBUG
+                                                          + ", " + 
ex.StackTrace
+#endif
+                    );
+                    return (null);
+                }
+
+                if (Method == null)
+                {
+                    await httpContext.Response.WriteError($"Unable to locate 
requested method (\"{mainParts[2]}\").");
+                    return (null);
+                }
+
+                if (Constructor == null)
+                {
+                    await httpContext.Response.WriteError($"Unable to locate 
appropriate constructor for (\"{mainParts[1]}\").");
+                    return (null);
+                }
+
+                Initialized = true;
+
+                await httpContext.Response.WriteResponse(200, "OK");
+
+                return (new Run(Type, Method, Constructor));
+            }
+            catch (Exception ex)
+            {
+                Console.Error.WriteLine(ex.StackTrace);
+                await httpContext.Response.WriteError(ex.Message
+#if DEBUG
+                                                  + ", " + ex.StackTrace
+#endif
+                );
+                Startup.WriteLogMarkers();
+                return (null);
+            }
+            finally
+            {
+                _initSemaphoreSlim.Release();
+            }
+        }
+    }
+}
diff --git a/core/dotnet3.0/proxy/Apache.OpenWhisk.Runtime.Common/Run.cs 
b/core/dotnet3.0/proxy/Apache.OpenWhisk.Runtime.Common/Run.cs
new file mode 100644
index 0000000..1ee35bb
--- /dev/null
+++ b/core/dotnet3.0/proxy/Apache.OpenWhisk.Runtime.Common/Run.cs
@@ -0,0 +1,109 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+using System;
+using System.IO;
+using System.Reflection;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Http;
+using Newtonsoft.Json.Linq;
+
+namespace Apache.OpenWhisk.Runtime.Common
+{
+    public class Run
+    {
+        private readonly Type _type;
+        private readonly MethodInfo _method;
+        private readonly ConstructorInfo _constructor;
+
+        public Run(Type type, MethodInfo method, ConstructorInfo constructor)
+        {
+            _type = type;
+            _method = method;
+            _constructor = constructor;
+        }
+
+        public async Task HandleRequest(HttpContext httpContext)
+        {
+            if (_type == null || _method == null || _constructor == null)
+            {
+                await httpContext.Response.WriteError("Cannot invoke an 
uninitialized action.");
+                return;
+            }
+
+            try
+            {
+                string body = await new 
StreamReader(httpContext.Request.Body).ReadToEndAsync();
+
+                JObject inputObject = string.IsNullOrEmpty(body) ? null : 
JObject.Parse(body);
+
+                JObject valObject = null;
+
+                if (inputObject != null)
+                {
+                    valObject = inputObject["value"] as JObject;
+                    foreach (JToken token in inputObject.Children())
+                    {
+                        try
+                        {
+                            if (token.Path.Equals("value", 
StringComparison.InvariantCultureIgnoreCase))
+                                continue;
+                            string envKey = 
$"__OW_{token.Path.ToUpperInvariant()}";
+                            string envVal = token.First.ToString();
+                            Environment.SetEnvironmentVariable(envKey, envVal);
+                            //Console.WriteLine($"Set environment variable 
\"{envKey}\" to \"{envVal}\".");
+                        }
+                        catch (Exception)
+                        {
+                            await Console.Error.WriteLineAsync(
+                                $"Unable to set environment variable for the 
\"{token.Path}\" token.");
+                        }
+                    }
+                }
+
+                object owObject = _constructor.Invoke(new object[] { });
+
+                try
+                {
+                    JObject output = (JObject) _method.Invoke(owObject, new 
object[] {valObject});
+
+                    if (output == null)
+                    {
+                        await httpContext.Response.WriteError("The action 
returned null");
+                        Console.Error.WriteLine("The action returned null");
+                        return;
+                    }
+
+                    await httpContext.Response.WriteResponse(200, 
output.ToString());
+                }
+                catch (Exception ex)
+                {
+                    Console.Error.WriteLine(ex.StackTrace);
+                    await httpContext.Response.WriteError(ex.Message
+#if DEBUG
+                                                          + ", " + 
ex.StackTrace
+#endif
+                    );
+                }
+            }
+            finally
+            {
+                Startup.WriteLogMarkers();
+            }
+        }
+    }
+}
diff --git a/core/dotnet3.0/proxy/Apache.OpenWhisk.Runtime.Common/Startup.cs 
b/core/dotnet3.0/proxy/Apache.OpenWhisk.Runtime.Common/Startup.cs
new file mode 100644
index 0000000..f11760c
--- /dev/null
+++ b/core/dotnet3.0/proxy/Apache.OpenWhisk.Runtime.Common/Startup.cs
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+using System;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Http;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging;
+
+namespace Apache.OpenWhisk.Runtime.Common
+{
+    public class Startup
+    {
+        public static void WriteLogMarkers()
+        {
+            Console.WriteLine("XXX_THE_END_OF_A_WHISK_ACTIVATION_XXX");
+            Console.Error.WriteLine("XXX_THE_END_OF_A_WHISK_ACTIVATION_XXX");
+        }
+        
+        public void Configure(IApplicationBuilder app)
+        {
+            PathString initPath = new PathString("/init");
+            PathString runPath = new PathString("/run");
+            Init init = new Init();
+            Run run = null;
+            app.Run(async (httpContext) =>
+                {
+                    if (httpContext.Request.Path.Equals(initPath))
+                    {
+                        run = await init.HandleRequest(httpContext);
+                        return;
+                    }
+
+                    if (httpContext.Request.Path.Equals(runPath))
+                    {
+                        if (!init.Initialized)
+                        {
+                            await httpContext.Response.WriteError("Cannot 
invoke an uninitialized action.");
+                            return;
+                        }
+
+                        if (run == null)
+                        {
+                            await httpContext.Response.WriteError("Cannot 
invoke an uninitialized action.");
+                            return;
+                        }
+
+                        await run.HandleRequest(httpContext);
+                    }
+                }
+            );
+        }
+    }
+}
diff --git 
a/tests/dotnet/Apache.OpenWhisk.Tests.Dotnet/Apache.OpenWhisk.Tests.Dotnet.csproj
 
b/core/dotnet3.0/proxy/Apache.OpenWhisk.Runtime.Dotnet.Minimal/Apache.OpenWhisk.Runtime.Dotnet.Minimal.csproj
similarity index 81%
copy from 
tests/dotnet/Apache.OpenWhisk.Tests.Dotnet/Apache.OpenWhisk.Tests.Dotnet.csproj
copy to 
core/dotnet3.0/proxy/Apache.OpenWhisk.Runtime.Dotnet.Minimal/Apache.OpenWhisk.Runtime.Dotnet.Minimal.csproj
index 2777248..452115d 100644
--- 
a/tests/dotnet/Apache.OpenWhisk.Tests.Dotnet/Apache.OpenWhisk.Tests.Dotnet.csproj
+++ 
b/core/dotnet3.0/proxy/Apache.OpenWhisk.Runtime.Dotnet.Minimal/Apache.OpenWhisk.Runtime.Dotnet.Minimal.csproj
@@ -17,11 +17,12 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
     <PropertyGroup>
-        <TargetFramework>netstandard2.0</TargetFramework>
+        <OutputType>Exe</OutputType>
+        <TargetFramework>netcoreapp3.0</TargetFramework>
     </PropertyGroup>
 
     <ItemGroup>
-      <PackageReference Include="Newtonsoft.Json" Version="12.0.1" />
+      <ProjectReference 
Include="..\Apache.OpenWhisk.Runtime.Common\Apache.OpenWhisk.Runtime.Common.csproj"
 />
     </ItemGroup>
 
 </Project>
diff --git a/tests/dotnet/Apache.OpenWhisk.Tests.Dotnet/Echo.cs 
b/core/dotnet3.0/proxy/Apache.OpenWhisk.Runtime.Dotnet.Minimal/Program.cs
similarity index 56%
copy from tests/dotnet/Apache.OpenWhisk.Tests.Dotnet/Echo.cs
copy to core/dotnet3.0/proxy/Apache.OpenWhisk.Runtime.Dotnet.Minimal/Program.cs
index ba39177..0eca9fa 100644
--- a/tests/dotnet/Apache.OpenWhisk.Tests.Dotnet/Echo.cs
+++ b/core/dotnet3.0/proxy/Apache.OpenWhisk.Runtime.Dotnet.Minimal/Program.cs
@@ -1,4 +1,4 @@
-/*
+/*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
  * this work for additional information regarding copyright ownership.
@@ -16,15 +16,29 @@
  */
 
 using System;
-using Newtonsoft.Json.Linq;
+using Apache.OpenWhisk.Runtime.Common;
+using Microsoft.AspNetCore;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.Extensions.Logging;
 
-namespace Apache.OpenWhisk.Tests.Dotnet
+namespace Apache.OpenWhisk.Runtime.Dotnet.Minimal
 {
-    public class Echo
+    class Program
     {
-        public JObject Main(JObject args)
+        static void Main(string[] args)
         {
-            return (args);
+            CreateWebHostBuilder(args).Build().Run();
         }
+        
+        public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
+            WebHost.CreateDefaultBuilder(args)
+                .ConfigureLogging((hostingContext, logging) =>
+                {
+                    logging.ClearProviders();
+                })
+               .SuppressStatusMessages(true)
+                .UseStartup<Startup>();
+
     }
 }
+
diff --git a/tests/dotnet/Apache.OpenWhisk.Tests.Dotnet/Nuller.cs 
b/core/dotnet3.0/proxy/build.gradle
similarity index 80%
copy from tests/dotnet/Apache.OpenWhisk.Tests.Dotnet/Nuller.cs
copy to core/dotnet3.0/proxy/build.gradle
index 6769f67..6a5d94e 100644
--- a/tests/dotnet/Apache.OpenWhisk.Tests.Dotnet/Nuller.cs
+++ b/core/dotnet3.0/proxy/build.gradle
@@ -15,15 +15,14 @@
  * limitations under the License.
  */
 
-using Newtonsoft.Json.Linq;
+plugins {
+  id "net.karlmartens.dotnet" version "0.2.20"
+}
+
+repositories {
+    mavenCentral()
+}
 
-namespace Apache.OpenWhisk.Tests.Dotnet
-{
-    public class Nuller
-    {
-        public JObject Main(JObject args)
-        {
-            return (null);
-        }
-    }
+dotnet {
+  configuration 'Release'
 }
diff --git a/core/dotnet3.0/proxy/gradle/wrapper/gradle-wrapper.jar 
b/core/dotnet3.0/proxy/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..f6b961f
Binary files /dev/null and 
b/core/dotnet3.0/proxy/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/core/dotnet2.2/CHANGELOG.md 
b/core/dotnet3.0/proxy/gradle/wrapper/gradle-wrapper.properties
similarity index 79%
copy from core/dotnet2.2/CHANGELOG.md
copy to core/dotnet3.0/proxy/gradle/wrapper/gradle-wrapper.properties
index dc50cac..d475d27 100644
--- a/core/dotnet2.2/CHANGELOG.md
+++ b/core/dotnet3.0/proxy/gradle/wrapper/gradle-wrapper.properties
@@ -1,4 +1,3 @@
-<!--
 #
 # Licensed to the Apache Software Foundation (ASF) under one or more
 # contributor license agreements.  See the NOTICE file distributed with
@@ -15,11 +14,8 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
--->
-
-# .NET Core 2.2 OpenWhisk Runtime Container
-
-
-## 1.13 (next Apache release)
-Changes:
-- Initial release
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-5.5.1-bin.zip
diff --git a/core/dotnet3.0/proxy/gradlew b/core/dotnet3.0/proxy/gradlew
new file mode 100644
index 0000000..d4ee78f
--- /dev/null
+++ b/core/dotnet3.0/proxy/gradlew
@@ -0,0 +1,188 @@
+#!/usr/bin/env sh
+
+#
+# Copyright 2015 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+##############################################################################
+##
+##  Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+    ls=`ls -ld "$PRG"`
+    link=`expr "$ls" : '.*-> \(.*\)$'`
+    if expr "$link" : '/.*' > /dev/null; then
+        PRG="$link"
+    else
+        PRG=`dirname "$PRG"`"/$link"
+    fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to 
pass JVM options to this script.
+DEFAULT_JVM_OPTS='-Dfile.encoding=UTF-8'
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+    echo "$*"
+}
+
+die () {
+    echo
+    echo "$*"
+    echo
+    exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+  CYGWIN* )
+    cygwin=true
+    ;;
+  Darwin* )
+    darwin=true
+    ;;
+  MINGW* )
+    msys=true
+    ;;
+  NONSTOP* )
+    nonstop=true
+    ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+        # IBM's JDK on AIX uses strange locations for the executables
+        JAVACMD="$JAVA_HOME/jre/sh/java"
+    else
+        JAVACMD="$JAVA_HOME/bin/java"
+    fi
+    if [ ! -x "$JAVACMD" ] ; then
+        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+    fi
+else
+    JAVACMD="java"
+    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 
'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; 
then
+    MAX_FD_LIMIT=`ulimit -H -n`
+    if [ $? -eq 0 ] ; then
+        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+            MAX_FD="$MAX_FD_LIMIT"
+        fi
+        ulimit -n $MAX_FD
+        if [ $? -ne 0 ] ; then
+            warn "Could not set maximum file descriptor limit: $MAX_FD"
+        fi
+    else
+        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+    fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" 
\"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+    JAVACMD=`cygpath --unix "$JAVACMD"`
+
+    # We build the pattern for arguments to be converted via cygpath
+    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+    SEP=""
+    for dir in $ROOTDIRSRAW ; do
+        ROOTDIRS="$ROOTDIRS$SEP$dir"
+        SEP="|"
+    done
+    OURCYGPATTERN="(^($ROOTDIRS))"
+    # Add a user-defined pattern to the cygpath arguments
+    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+    fi
+    # Now convert the arguments - kludge to limit ourselves to /bin/sh
+    i=0
+    for arg in "$@" ; do
+        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### 
Determine if an option
+
+        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### 
Added a condition
+            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+        else
+            eval `echo args$i`="\"$arg\""
+        fi
+        i=$((i+1))
+    done
+    case $i in
+        (0) set -- ;;
+        (1) set -- "$args0" ;;
+        (2) set -- "$args0" "$args1" ;;
+        (3) set -- "$args0" "$args1" "$args2" ;;
+        (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+        (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+        (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+        (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" 
"$args6" ;;
+        (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" 
"$args6" "$args7" ;;
+        (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" 
"$args6" "$args7" "$args8" ;;
+    esac
+fi
+
+# Escape application args
+save () {
+    for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; 
done
+    echo " "
+}
+APP_ARGS=$(save "$@")
+
+# Collect all arguments for the java command, following the shell quoting and 
substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 
"\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" 
org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+# by default we should be in the correct project dir, but when run from Finder 
on Mac, the cwd is wrong
+if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
+  cd "$(dirname "$0")"
+fi
+
+exec "$JAVACMD" "$@"
diff --git a/core/dotnet3.0/proxy/gradlew.bat b/core/dotnet3.0/proxy/gradlew.bat
new file mode 100644
index 0000000..ad0ff10
--- /dev/null
+++ b/core/dotnet3.0/proxy/gradlew.bat
@@ -0,0 +1,100 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem      http://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem  Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS 
to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=-Dfile.encoding=UTF-8
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your 
PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% 
"-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" 
org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code 
instead of
+rem the _cmd.exe /c_ return code!
+if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/tests/dotnet/openwhisk-tests-dotnet.sln 
b/core/dotnet3.0/proxy/openwhisk-runtime-dotnet.sln
similarity index 56%
copy from tests/dotnet/openwhisk-tests-dotnet.sln
copy to core/dotnet3.0/proxy/openwhisk-runtime-dotnet.sln
index a11b7e0..25e60cc 100644
--- a/tests/dotnet/openwhisk-tests-dotnet.sln
+++ b/core/dotnet3.0/proxy/openwhisk-runtime-dotnet.sln
@@ -17,7 +17,9 @@
 # limitations under the License.
 #
 
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = 
"Apache.OpenWhisk.Tests.Dotnet", 
"Apache.OpenWhisk.Tests.Dotnet\Apache.OpenWhisk.Tests.Dotnet.csproj", 
"{84C21ADE-CF95-4027-B478-DB5BA078178A}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = 
"Apache.OpenWhisk.Runtime.Dotnet.Minimal", 
"Apache.OpenWhisk.Runtime.Dotnet.Minimal\Apache.OpenWhisk.Runtime.Dotnet.Minimal.csproj",
 "{F76F51C9-EB3B-4D4C-89C0-A71E0BEF88DC}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = 
"Apache.OpenWhisk.Runtime.Common", 
"Apache.OpenWhisk.Runtime.Common\Apache.OpenWhisk.Runtime.Common.csproj", 
"{26ADD70B-3101-4943-982C-16D380D4B044}"
 EndProject
 Global
        GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -25,9 +27,13 @@ Global
                Release|Any CPU = Release|Any CPU
        EndGlobalSection
        GlobalSection(ProjectConfigurationPlatforms) = postSolution
-               {84C21ADE-CF95-4027-B478-DB5BA078178A}.Debug|Any CPU.ActiveCfg 
= Debug|Any CPU
-               {84C21ADE-CF95-4027-B478-DB5BA078178A}.Debug|Any CPU.Build.0 = 
Debug|Any CPU
-               {84C21ADE-CF95-4027-B478-DB5BA078178A}.Release|Any 
CPU.ActiveCfg = Release|Any CPU
-               {84C21ADE-CF95-4027-B478-DB5BA078178A}.Release|Any CPU.Build.0 
= Release|Any CPU
+               {F76F51C9-EB3B-4D4C-89C0-A71E0BEF88DC}.Debug|Any CPU.ActiveCfg 
= Debug|Any CPU
+               {F76F51C9-EB3B-4D4C-89C0-A71E0BEF88DC}.Debug|Any CPU.Build.0 = 
Debug|Any CPU
+               {F76F51C9-EB3B-4D4C-89C0-A71E0BEF88DC}.Release|Any 
CPU.ActiveCfg = Release|Any CPU
+               {F76F51C9-EB3B-4D4C-89C0-A71E0BEF88DC}.Release|Any CPU.Build.0 
= Release|Any CPU
+               {26ADD70B-3101-4943-982C-16D380D4B044}.Debug|Any CPU.ActiveCfg 
= Debug|Any CPU
+               {26ADD70B-3101-4943-982C-16D380D4B044}.Debug|Any CPU.Build.0 = 
Debug|Any CPU
+               {26ADD70B-3101-4943-982C-16D380D4B044}.Release|Any 
CPU.ActiveCfg = Release|Any CPU
+               {26ADD70B-3101-4943-982C-16D380D4B044}.Release|Any CPU.Build.0 
= Release|Any CPU
        EndGlobalSection
 EndGlobal
diff --git a/settings.gradle b/settings.gradle
index c7465fe..d787614 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -16,11 +16,15 @@
  */
 
 include ':tests'
-include ':tests:dotnet'
+include ':tests:dotnet2.2'
+include ':tests:dotnet3.0'
 
 include ':core:dotnet2.2'
 include ':core:dotnet2.2:proxy'
 
+include ':core:dotnet3.0'
+include ':core:dotnet3.0:proxy'
+
 rootProject.name = 'runtime-dotnet'
 
 gradle.ext.openwhisk = [
diff --git a/tests/build.gradle b/tests/build.gradle
index 2b8c6ce..2cfb28f 100644
--- a/tests/build.gradle
+++ b/tests/build.gradle
@@ -43,5 +43,6 @@ tasks.withType(ScalaCompile) {
 }
 
 compileTestScala {
-    dependsOn ':tests:dotnet:prepare'
+    dependsOn ':tests:dotnet2.2:prepare'
+    dependsOn ':tests:dotnet3.0:prepare'
 }
diff --git 
a/tests/dotnet/Apache.OpenWhisk.Tests.Dotnet/Apache.OpenWhisk.Tests.Dotnet.csproj
 
b/tests/dotnet2.2/Apache.OpenWhisk.Tests.Dotnet/Apache.OpenWhisk.Tests.Dotnet.csproj
similarity index 91%
copy from 
tests/dotnet/Apache.OpenWhisk.Tests.Dotnet/Apache.OpenWhisk.Tests.Dotnet.csproj
copy to 
tests/dotnet2.2/Apache.OpenWhisk.Tests.Dotnet/Apache.OpenWhisk.Tests.Dotnet.csproj
index 2777248..05df906 100644
--- 
a/tests/dotnet/Apache.OpenWhisk.Tests.Dotnet/Apache.OpenWhisk.Tests.Dotnet.csproj
+++ 
b/tests/dotnet2.2/Apache.OpenWhisk.Tests.Dotnet/Apache.OpenWhisk.Tests.Dotnet.csproj
@@ -24,4 +24,9 @@
       <PackageReference Include="Newtonsoft.Json" Version="12.0.1" />
     </ItemGroup>
 
+    <ItemGroup>
+      <Compile Include="..\..\dotnetshared\*.cs">
+      </Compile>
+    </ItemGroup>
+
 </Project>
diff --git a/tests/dotnet/build.gradle b/tests/dotnet2.2/build.gradle
similarity index 97%
copy from tests/dotnet/build.gradle
copy to tests/dotnet2.2/build.gradle
index 5efdad1..377f659 100644
--- a/tests/dotnet/build.gradle
+++ b/tests/dotnet2.2/build.gradle
@@ -42,7 +42,7 @@ task prepare_zip(type: Zip, dependsOn: prepare_distro) {
   from file('build/dist/out')
   include '*'
   include '**/**'
-  archiveName 'dotnettests.zip'
+  archiveName 'dotnettests2.2.zip'
   destinationDir(file('../src/test/resources'))
 }
 
diff --git a/tests/dotnet/openwhisk-tests-dotnet.sln 
b/tests/dotnet2.2/openwhisk-tests-dotnet.sln
similarity index 100%
copy from tests/dotnet/openwhisk-tests-dotnet.sln
copy to tests/dotnet2.2/openwhisk-tests-dotnet.sln
diff --git 
a/tests/dotnet/Apache.OpenWhisk.Tests.Dotnet/Apache.OpenWhisk.Tests.Dotnet.csproj
 
b/tests/dotnet3.0/Apache.OpenWhisk.Tests.Dotnet/Apache.OpenWhisk.Tests.Dotnet.csproj
similarity index 85%
rename from 
tests/dotnet/Apache.OpenWhisk.Tests.Dotnet/Apache.OpenWhisk.Tests.Dotnet.csproj
rename to 
tests/dotnet3.0/Apache.OpenWhisk.Tests.Dotnet/Apache.OpenWhisk.Tests.Dotnet.csproj
index 2777248..ddc5679 100644
--- 
a/tests/dotnet/Apache.OpenWhisk.Tests.Dotnet/Apache.OpenWhisk.Tests.Dotnet.csproj
+++ 
b/tests/dotnet3.0/Apache.OpenWhisk.Tests.Dotnet/Apache.OpenWhisk.Tests.Dotnet.csproj
@@ -17,11 +17,16 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
     <PropertyGroup>
-        <TargetFramework>netstandard2.0</TargetFramework>
+        <TargetFramework>netstandard2.1</TargetFramework>
     </PropertyGroup>
 
     <ItemGroup>
-      <PackageReference Include="Newtonsoft.Json" Version="12.0.1" />
+      <PackageReference Include="Newtonsoft.Json" Version="12.0.2" />
     </ItemGroup>
 
+    <ItemGroup>
+      <Compile Include="..\..\dotnetshared\*.cs">
+      </Compile>
+    </ItemGroup>
+    
 </Project>
diff --git a/tests/dotnet/build.gradle b/tests/dotnet3.0/build.gradle
similarity index 93%
rename from tests/dotnet/build.gradle
rename to tests/dotnet3.0/build.gradle
index 5efdad1..8c2e65e 100644
--- a/tests/dotnet/build.gradle
+++ b/tests/dotnet3.0/build.gradle
@@ -30,11 +30,10 @@ dotnet {
 task prepare_distro(dependsOn: distribution) {
   doLast {
     copy {
-      from tarTree(resources.gzip(file('build/dist/netstandard2.0.tar.gz')))
+      from tarTree(resources.gzip(file('build/dist/netstandard2.1.tar.gz')))
       into file('build/dist/out')
     }
-
-    delete file('build/dist/netstandard2.0.tar.gz')
+    delete file('build/dist/netstandard2.1.tar.gz')
   }
 }
 
@@ -42,7 +41,7 @@ task prepare_zip(type: Zip, dependsOn: prepare_distro) {
   from file('build/dist/out')
   include '*'
   include '**/**'
-  archiveName 'dotnettests.zip'
+  archiveName 'dotnettests3.0.zip'
   destinationDir(file('../src/test/resources'))
 }
 
diff --git a/tests/dotnet/openwhisk-tests-dotnet.sln 
b/tests/dotnet3.0/openwhisk-tests-dotnet.sln
similarity index 80%
rename from tests/dotnet/openwhisk-tests-dotnet.sln
rename to tests/dotnet3.0/openwhisk-tests-dotnet.sln
index a11b7e0..0f4ec0d 100644
--- a/tests/dotnet/openwhisk-tests-dotnet.sln
+++ b/tests/dotnet3.0/openwhisk-tests-dotnet.sln
@@ -17,7 +17,7 @@
 # limitations under the License.
 #
 
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = 
"Apache.OpenWhisk.Tests.Dotnet", 
"Apache.OpenWhisk.Tests.Dotnet\Apache.OpenWhisk.Tests.Dotnet.csproj", 
"{84C21ADE-CF95-4027-B478-DB5BA078178A}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = 
"Apache.OpenWhisk.Tests.Dotnet", 
"Apache.OpenWhisk.Tests.Dotnet\Apache.OpenWhisk.Tests.Dotnet.csproj", 
"{4DA37A8E-7505-4C51-8C75-B18BDA45392C}"
 EndProject
 Global
        GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -25,9 +25,9 @@ Global
                Release|Any CPU = Release|Any CPU
        EndGlobalSection
        GlobalSection(ProjectConfigurationPlatforms) = postSolution
-               {84C21ADE-CF95-4027-B478-DB5BA078178A}.Debug|Any CPU.ActiveCfg 
= Debug|Any CPU
-               {84C21ADE-CF95-4027-B478-DB5BA078178A}.Debug|Any CPU.Build.0 = 
Debug|Any CPU
-               {84C21ADE-CF95-4027-B478-DB5BA078178A}.Release|Any 
CPU.ActiveCfg = Release|Any CPU
-               {84C21ADE-CF95-4027-B478-DB5BA078178A}.Release|Any CPU.Build.0 
= Release|Any CPU
+               {4DA37A8E-7505-4C51-8C75-B18BDA45392C}.Debug|Any CPU.ActiveCfg 
= Debug|Any CPU
+               {4DA37A8E-7505-4C51-8C75-B18BDA45392C}.Debug|Any CPU.Build.0 = 
Debug|Any CPU
+               {4DA37A8E-7505-4C51-8C75-B18BDA45392C}.Release|Any 
CPU.ActiveCfg = Release|Any CPU
+               {4DA37A8E-7505-4C51-8C75-B18BDA45392C}.Release|Any CPU.Build.0 
= Release|Any CPU
        EndGlobalSection
 EndGlobal
diff --git a/tests/dotnet/Apache.OpenWhisk.Tests.Dotnet/AltEcho.cs 
b/tests/dotnetshared/AltEcho.cs
similarity index 100%
rename from tests/dotnet/Apache.OpenWhisk.Tests.Dotnet/AltEcho.cs
rename to tests/dotnetshared/AltEcho.cs
diff --git a/tests/dotnet/Apache.OpenWhisk.Tests.Dotnet/Echo.cs 
b/tests/dotnetshared/Echo.cs
similarity index 100%
rename from tests/dotnet/Apache.OpenWhisk.Tests.Dotnet/Echo.cs
rename to tests/dotnetshared/Echo.cs
diff --git a/tests/dotnet/Apache.OpenWhisk.Tests.Dotnet/Environment.cs 
b/tests/dotnetshared/Environment.cs
similarity index 100%
rename from tests/dotnet/Apache.OpenWhisk.Tests.Dotnet/Environment.cs
rename to tests/dotnetshared/Environment.cs
diff --git a/tests/dotnet/Apache.OpenWhisk.Tests.Dotnet/Error.cs 
b/tests/dotnetshared/Error.cs
similarity index 78%
rename from tests/dotnet/Apache.OpenWhisk.Tests.Dotnet/Error.cs
rename to tests/dotnetshared/Error.cs
index f98068f..7492475 100644
--- a/tests/dotnet/Apache.OpenWhisk.Tests.Dotnet/Error.cs
+++ b/tests/dotnetshared/Error.cs
@@ -16,6 +16,8 @@
  */
 
 using Newtonsoft.Json.Linq;
+using System.Runtime.Versioning;
+using System.Reflection;
 
 namespace Apache.OpenWhisk.Tests.Dotnet
 {
@@ -24,7 +26,12 @@ namespace Apache.OpenWhisk.Tests.Dotnet
         public JObject Main(JObject args)
         {
             JObject message = new JObject();
-            message.Add("error", new JValue("This action is unhappy."));
+            var framework = Assembly
+                .GetEntryAssembly()?
+                .GetCustomAttribute<TargetFrameworkAttribute>()?
+                .FrameworkName;
+
+            message.Add("error", new JValue(framework));
             return (message);
         }
     }
diff --git a/tests/dotnet/Apache.OpenWhisk.Tests.Dotnet/Exception.cs 
b/tests/dotnetshared/Exception.cs
similarity index 100%
rename from tests/dotnet/Apache.OpenWhisk.Tests.Dotnet/Exception.cs
rename to tests/dotnetshared/Exception.cs
diff --git a/tests/dotnet/Apache.OpenWhisk.Tests.Dotnet/NonEmptyConstructor.cs 
b/tests/dotnetshared/NonEmptyConstructor.cs
similarity index 100%
rename from tests/dotnet/Apache.OpenWhisk.Tests.Dotnet/NonEmptyConstructor.cs
rename to tests/dotnetshared/NonEmptyConstructor.cs
diff --git a/tests/dotnet/Apache.OpenWhisk.Tests.Dotnet/Nuller.cs 
b/tests/dotnetshared/Nuller.cs
similarity index 100%
rename from tests/dotnet/Apache.OpenWhisk.Tests.Dotnet/Nuller.cs
rename to tests/dotnetshared/Nuller.cs
diff --git a/tests/dotnet/Apache.OpenWhisk.Tests.Dotnet/Unicode.cs 
b/tests/dotnetshared/Unicode.cs
similarity index 100%
rename from tests/dotnet/Apache.OpenWhisk.Tests.Dotnet/Unicode.cs
rename to tests/dotnetshared/Unicode.cs
diff --git 
a/tests/src/test/scala/actionContainers/DotNetActionContainerTests.scala 
b/tests/src/test/scala/actionContainers/DotNet2_2ActionContainerTests.scala
similarity index 96%
copy from tests/src/test/scala/actionContainers/DotNetActionContainerTests.scala
copy to 
tests/src/test/scala/actionContainers/DotNet2_2ActionContainerTests.scala
index 6dfa575..6f84f75 100644
--- a/tests/src/test/scala/actionContainers/DotNetActionContainerTests.scala
+++ b/tests/src/test/scala/actionContainers/DotNet2_2ActionContainerTests.scala
@@ -25,8 +25,8 @@ import actionContainers.ActionContainer.withContainer
 import java.nio.file.Paths
 
 @RunWith(classOf[JUnitRunner])
-class DotNetActionContainerTests extends BasicActionRunnerTests with 
WskActorSystem {
-  val functionb64 = 
ResourceHelpers.readAsBase64(Paths.get(getClass.getResource("/dotnettests.zip").getPath))
+class DotNet2_2ActionContainerTests extends BasicActionRunnerTests with 
WskActorSystem {
+  val functionb64 = 
ResourceHelpers.readAsBase64(Paths.get(getClass.getResource("/dotnettests2.2.zip").getPath))
 
   // Helpers specific to java actions
   override def withActionContainer(env: Map[String, String] = Map.empty)(
@@ -110,7 +110,10 @@ class DotNetActionContainerTests extends 
BasicActionRunnerTests with WskActorSys
       runCode should be(200)
 
       runRes shouldBe defined
-      runRes.get.fields.get("error") shouldBe defined
+
+      runRes should {
+        be(Some(JsObject("error" -> JsString(".NETCoreApp,Version=v2.2"))))
+      }
     }
 
     checkStreams(out, err, {
diff --git 
a/tests/src/test/scala/actionContainers/DotNetActionContainerTests.scala 
b/tests/src/test/scala/actionContainers/DotNet3_0ActionContainerTests.scala
similarity index 96%
rename from 
tests/src/test/scala/actionContainers/DotNetActionContainerTests.scala
rename to 
tests/src/test/scala/actionContainers/DotNet3_0ActionContainerTests.scala
index 6dfa575..ec937ab 100644
--- a/tests/src/test/scala/actionContainers/DotNetActionContainerTests.scala
+++ b/tests/src/test/scala/actionContainers/DotNet3_0ActionContainerTests.scala
@@ -25,12 +25,12 @@ import actionContainers.ActionContainer.withContainer
 import java.nio.file.Paths
 
 @RunWith(classOf[JUnitRunner])
-class DotNetActionContainerTests extends BasicActionRunnerTests with 
WskActorSystem {
-  val functionb64 = 
ResourceHelpers.readAsBase64(Paths.get(getClass.getResource("/dotnettests.zip").getPath))
+class DotNet3_0ActionContainerTests extends BasicActionRunnerTests with 
WskActorSystem {
+  val functionb64 = 
ResourceHelpers.readAsBase64(Paths.get(getClass.getResource("/dotnettests3.0.zip").getPath))
 
   // Helpers specific to java actions
   override def withActionContainer(env: Map[String, String] = Map.empty)(
-    code: ActionContainer => Unit): (String, String) = 
withContainer("action-dotnet-v2.2", env)(code)
+    code: ActionContainer => Unit): (String, String) = 
withContainer("action-dotnet-v3.0", env)(code)
 
   behavior of "dotnet action"
 
@@ -110,7 +110,10 @@ class DotNetActionContainerTests extends 
BasicActionRunnerTests with WskActorSys
       runCode should be(200)
 
       runRes shouldBe defined
-      runRes.get.fields.get("error") shouldBe defined
+
+      runRes should {
+        be(Some(JsObject("error" -> JsString(".NETCoreApp,Version=v3.0"))))
+      }
     }
 
     checkStreams(out, err, {
diff --git a/tools/travis/build.sh b/tools/travis/build.sh
index c75ab77..14db490 100755
--- a/tools/travis/build.sh
+++ b/tools/travis/build.sh
@@ -36,15 +36,15 @@ curl -fsSL https://get.docker.com -o get-docker.sh
 sudo sh get-docker.sh
 docker version
 
-# Upgrade dpkg avoid problems installing dotnet 2.2
+# Upgrade dpkg avoid problems installing dotnet 3.0
 # https://github.com/travis-ci/travis-ci/issues/9361#issuecomment-408431262
 sudo apt-get install -y --force-yes -q -qq dpkg
 # Install dotnet
-wget -q 
https://packages.microsoft.com/config/ubuntu/14.04/packages-microsoft-prod.deb
+wget -q 
https://packages.microsoft.com/config/ubuntu/16.04/packages-microsoft-prod.deb
 sudo dpkg -i packages-microsoft-prod.deb
 sudo apt-get install -y apt-transport-https
 sudo apt-get -y update -qq
-sudo apt-get install -y dotnet-sdk-2.2
+sudo apt-get install -y dotnet-sdk-3.0
 
 # Build OpenWhisk deps before we run tests
 cd $WHISKDIR

Reply via email to