diff --git a/README.md b/README.md index 1100205..335e95a 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,105 @@ [![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.com/apache/openwhisk-runtime-dotnet.svg?branch=master)](https://travis-ci.com/github/apache/openwhisk-runtime-dotnet) +## Give it a try today + +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.zip * +``` + +Create the action + +```bash +wsk action update helloDotNet helloDotNet.zip --main Apache.OpenWhisk.Example.Dotnet::Apache.OpenWhisk.Example.Dotnet.Hello::Main --kind dotnet:2.2 +``` + +For the return result, not only support `dictionary` but also support `array` + +So a very simple `hello array` function would be: + +```csharp +using System; +using Newtonsoft.Json.Linq; + +namespace Apache.OpenWhisk.Tests.Dotnet +{ + public class HelloArray + { + public JArray Main(JObject args) + { + JArray jarray = new JArray(); + jarray.Add("a"); + jarray.Add("b"); + return (jarray); + } + } +} +``` + +And support array result for sequence action as well, the first action's array result can be used as next action's input parameter. + +So the function can be: + +```csharp +using System; +using Newtonsoft.Json.Linq; + +namespace Apache.OpenWhisk.Tests.Dotnet +{ + public class HelloPassArrayParam + { + public JArray Main(JArray args) + { + return (args); + } + } +} +``` ## Changelogs 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 98551fe..d9c9df2 100644 --- a/core/dotnet2.2/proxy/Apache.OpenWhisk.Runtime.Common/Run.cs +++ b/core/dotnet2.2/proxy/Apache.OpenWhisk.Runtime.Common/Run.cs @@ -54,6 +54,7 @@ public async Task HandleRequest(HttpContext httpContext) JObject inputObject = string.IsNullOrEmpty(body) ? null : JObject.Parse(body); JObject valObject = null; + JArray valArray = null; if (inputObject != null) { @@ -76,18 +77,29 @@ await Console.Error.WriteLineAsync( } } } + if (valObject == null) { + valArray = inputObject["value"] as JArray; + } object owObject = _constructor.Invoke(new object[] { }); try { - JObject output; + JContainer output; if(_awaitableMethod) { - output = (JObject) await (dynamic) _method.Invoke(owObject, new object[] {valObject}); + if (valObject != null) { + output = (JContainer) await (dynamic) _method.Invoke(owObject, new object[] {valObject}); + } else { + output = (JContainer) await (dynamic) _method.Invoke(owObject, new object[] {valArray}); + } } else { - output = (JObject) _method.Invoke(owObject, new object[] {valObject}); + if (valObject != null) { + output = (JContainer) _method.Invoke(owObject, new object[] {valObject}); + } else { + output = (JContainer) _method.Invoke(owObject, new object[] {valArray}); + } } if (output == null) diff --git a/core/dotnet3.1/proxy/Apache.OpenWhisk.Runtime.Common/Run.cs b/core/dotnet3.1/proxy/Apache.OpenWhisk.Runtime.Common/Run.cs index 98551fe..0ee99ce 100644 --- a/core/dotnet3.1/proxy/Apache.OpenWhisk.Runtime.Common/Run.cs +++ b/core/dotnet3.1/proxy/Apache.OpenWhisk.Runtime.Common/Run.cs @@ -54,6 +54,7 @@ public async Task HandleRequest(HttpContext httpContext) JObject inputObject = string.IsNullOrEmpty(body) ? null : JObject.Parse(body); JObject valObject = null; + JArray valArray = null; if (inputObject != null) { @@ -75,19 +76,30 @@ await Console.Error.WriteLineAsync( $"Unable to set environment variable for the \"{token.Path}\" token."); } } + if (valObject == null) { + valArray = inputObject["value"] as JArray; + } } object owObject = _constructor.Invoke(new object[] { }); try { - JObject output; + JContainer output; if(_awaitableMethod) { - output = (JObject) await (dynamic) _method.Invoke(owObject, new object[] {valObject}); + if (valObject != null) { + output = (JContainer) await (dynamic) _method.Invoke(owObject, new object[] {valObject}); + } else { + output = (JContainer) await (dynamic) _method.Invoke(owObject, new object[] {valArray}); + } } else { - output = (JObject) _method.Invoke(owObject, new object[] {valObject}); + if (valObject != null) { + output = (JContainer) _method.Invoke(owObject, new object[] {valObject}); + } else { + output = (JContainer) _method.Invoke(owObject, new object[] {valArray}); + } } if (output == null) diff --git a/tests/dotnetshared/HelloArray.cs b/tests/dotnetshared/HelloArray.cs new file mode 100644 index 0000000..b9c7d22 --- /dev/null +++ b/tests/dotnetshared/HelloArray.cs @@ -0,0 +1,33 @@ +/* + * 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 Newtonsoft.Json.Linq; + +namespace Apache.OpenWhisk.Tests.Dotnet +{ + public class HelloArray + { + public JArray Main(JObject args) + { + JArray jarray = new JArray(); + jarray.Add("a"); + jarray.Add("b"); + return (jarray); + } + } +} diff --git a/tests/dotnetshared/HelloPassArrayParam.cs b/tests/dotnetshared/HelloPassArrayParam.cs new file mode 100644 index 0000000..15458e2 --- /dev/null +++ b/tests/dotnetshared/HelloPassArrayParam.cs @@ -0,0 +1,30 @@ +/* + * 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 Newtonsoft.Json.Linq; + +namespace Apache.OpenWhisk.Tests.Dotnet +{ + public class HelloPassArrayParam + { + public JArray Main(JArray args) + { + return (args); + } + } +} diff --git a/tests/src/test/scala/actionContainers/DotNet2_2ActionContainerTests.scala b/tests/src/test/scala/actionContainers/DotNet2_2ActionContainerTests.scala index 0a5b1b8..7a15249 100644 --- a/tests/src/test/scala/actionContainers/DotNet2_2ActionContainerTests.scala +++ b/tests/src/test/scala/actionContainers/DotNet2_2ActionContainerTests.scala @@ -231,4 +231,32 @@ class DotNet2_2ActionContainerTests extends BasicActionRunnerTests with WskActor (o + e).toLowerCase should include("the action returned null") }) } + + it should "support return array result" in { + val (out, err) = withActionContainer() { c => + val (initCode, _) = + c.init( + initPayload(functionb64, "Apache.OpenWhisk.Tests.Dotnet::Apache.OpenWhisk.Tests.Dotnet.HelloArray::Main")) + initCode should be(200) + + val (runCode, runRes) = c.runForJsArray(runPayload(JsObject())) + runCode should be(200) + runRes shouldBe Some(JsArray(JsString("a"), JsString("b"))) + } + } + + it should "support array as input param" in { + val (out, err) = withActionContainer() { c => + val (initCode, _) = + c.init( + initPayload( + functionb64, + "Apache.OpenWhisk.Tests.Dotnet::Apache.OpenWhisk.Tests.Dotnet.HelloPassArrayParam::Main")) + initCode should be(200) + + val (runCode, runRes) = c.runForJsArray(runPayload(JsArray(JsString("a"), JsString("b")))) + runCode should be(200) + runRes shouldBe Some(JsArray(JsString("a"), JsString("b"))) + } + } } diff --git a/tests/src/test/scala/actionContainers/DotNet3_1ActionContainerTests.scala b/tests/src/test/scala/actionContainers/DotNet3_1ActionContainerTests.scala index 8436252..dc9ee90 100644 --- a/tests/src/test/scala/actionContainers/DotNet3_1ActionContainerTests.scala +++ b/tests/src/test/scala/actionContainers/DotNet3_1ActionContainerTests.scala @@ -235,4 +235,32 @@ class DotNet3_1ActionContainerTests extends BasicActionRunnerTests with WskActor (o + e).toLowerCase should include("the action returned null") }) } + + it should "support return array result" in { + val (out, err) = withActionContainer() { c => + val (initCode, _) = + c.init( + initPayload(functionb64, "Apache.OpenWhisk.Tests.Dotnet::Apache.OpenWhisk.Tests.Dotnet.HelloArray::Main")) + initCode should be(200) + + val (runCode, runRes) = c.runForJsArray(runPayload(JsObject())) + runCode should be(200) + runRes shouldBe Some(JsArray(JsString("a"), JsString("b"))) + } + } + + it should "support array as input param" in { + val (out, err) = withActionContainer() { c => + val (initCode, _) = + c.init( + initPayload( + functionb64, + "Apache.OpenWhisk.Tests.Dotnet::Apache.OpenWhisk.Tests.Dotnet.HelloPassArrayParam::Main")) + initCode should be(200) + + val (runCode, runRes) = c.runForJsArray(runPayload(JsArray(JsString("a"), JsString("b")))) + runCode should be(200) + runRes shouldBe Some(JsArray(JsString("a"), JsString("b"))) + } + } } diff --git a/tests/src/test/scala/actionContainers/DotNet3_1ActionContainerTests_2_2.scala b/tests/src/test/scala/actionContainers/DotNet3_1ActionContainerTests_2_2.scala index 6a8db7f..b3c9a99 100644 --- a/tests/src/test/scala/actionContainers/DotNet3_1ActionContainerTests_2_2.scala +++ b/tests/src/test/scala/actionContainers/DotNet3_1ActionContainerTests_2_2.scala @@ -235,4 +235,32 @@ class DotNet3_1ActionContainerTests_2_2 extends BasicActionRunnerTests with WskA (o + e).toLowerCase should include("the action returned null") }) } + + it should "support return array result" in { + val (out, err) = withActionContainer() { c => + val (initCode, _) = + c.init( + initPayload(functionb64, "Apache.OpenWhisk.Tests.Dotnet::Apache.OpenWhisk.Tests.Dotnet.HelloArray::Main")) + initCode should be(200) + + val (runCode, runRes) = c.runForJsArray(runPayload(JsObject())) + runCode should be(200) + runRes shouldBe Some(JsArray(JsString("a"), JsString("b"))) + } + } + + it should "support array as input param" in { + val (out, err) = withActionContainer() { c => + val (initCode, _) = + c.init( + initPayload( + functionb64, + "Apache.OpenWhisk.Tests.Dotnet::Apache.OpenWhisk.Tests.Dotnet.HelloPassArrayParam::Main")) + initCode should be(200) + + val (runCode, runRes) = c.runForJsArray(runPayload(JsArray(JsString("a"), JsString("b")))) + runCode should be(200) + runRes shouldBe Some(JsArray(JsString("a"), JsString("b"))) + } + } }