apache/openwhisk-runtime-dotnet

Remove dependency on 3rd party JSON library from next version of runtime

mattwelke opened this issue · 2 comments

Based on conversation in #34 and #50...

Problem:

OpenWhisk users creating .NET actions need to add a dependency on a 3rd party JSON library (currently Newtonsoft.Json as of the dotnet:3.1 runtime) because the contract between action and runtime provides the action main function with a JObject via paramter and requires the main function to return a JObject.

Consequences:

  • This adds friction to creating an action (User: "Why do I need to use this 3rd party library?")
  • Can result in errors when the versions of the 3rd party library differ between the runtime and the action. Testing so far has found that it's okay for a runtime to use a version of Newtonsoft.Json with a higher major version than the action, but the actions don't run because of an error loading the action code for the other way around.

Potential solution:

Since the contract between runtimes and actions is really just an arbitrary map of data (as seen in the Node.js runtime instructions as https://github.com/apache/openwhisk/blob/master/docs/actions-nodejs.md where they just return { done: true } and { message: 'my message' } etc), use a map data structure for this contract. C# and other CLR languages supported by the .NET runtime like VB.NET have Dictionary for that (https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.dictionary-2?view=net-5.0). If the map data structure type changes between runtimes, like moving from .NET Core 3.1 to .NET 6 for example, OpenWhisk users would be instructed via documentation for the new runtime to use a different type from the standard library of the language.

That way, all versions of the runtime and every action ever created for the runtime would not depend on things that need major version updates throughout the lifecycle of a runtime (like dotnet:3.1). The runtime would control the implementation of how JSON is handled. It could choose for example between different versions of Newtonsoft.Json or even other JSON libraries like System.Text.Json whenever it wants, with the runtime versions being updated without the action implementers ever having to worry about it.

I decided to test this out and include an example if I got it working. Yep, it works! #52 shows the changes I made to the 3.1 runtime to make it work without Newtonsoft.Json on the action side of things (JSON is still needed on the runtime side of things, in order to fulfill its contract with the OpenWhisk system which speaks JSON).

My build of the changed runtime is public at https://hub.docker.com/repository/docker/mwelke/openwhisk-runtime-dotnet-v3.1-nojson if anyone wants to play with it.

I made a test action to demonstrate it (https://github.com/mattwelke/openwhisk-dotnet-runtime-v3.1-nojson-test). deploy.sh in that repo shows how I deployed it to IBM Cloud Function as a custom runtime action (after logging into ibmcloud CLI).

For convenience, here's the code repeated here for my action in that repo:

using System.Collections.Generic;

namespace OpenWhiskDotnetNoJsonTest
{
    public class Class1
    {
        public Dictionary<string, object> Main(Dictionary<string, object> owParams)
        {
            var output = new Dictionary<string, object>();
            foreach (var owParam in owParams)
            {
                output.Add(owParam.Key, owParam.Value);
            }

            output.Add("success", true);
            
            return output;
        }
    }
}

I configured a parameter:

image

And it works! It has access to the parameter, and returns things to OpenWhisk nicely (via Dictionary):

image