From f3c3e29ef789b6453dcf587ce0249de1582cab8b Mon Sep 17 00:00:00 2001
From: Guillermo Leon <18090460+gleono@users.noreply.github.com>
Date: Tue, 24 Sep 2024 21:11:33 -0500
Subject: [PATCH 1/5] Enable nullable type references
---
.../Apache.OpenWhisk.Runtime.Common.csproj | 1 +
.../Apache.OpenWhisk.Runtime.Common/Init.cs | 68 ++++++++++---------
.../Apache.OpenWhisk.Runtime.Common/Run.cs | 26 +++----
.../Startup.cs | 8 +--
...he.OpenWhisk.Runtime.Dotnet.Minimal.csproj | 1 +
5 files changed, 54 insertions(+), 50 deletions(-)
diff --git a/core/net6.0/proxy/Apache.OpenWhisk.Runtime.Common/Apache.OpenWhisk.Runtime.Common.csproj b/core/net6.0/proxy/Apache.OpenWhisk.Runtime.Common/Apache.OpenWhisk.Runtime.Common.csproj
index 023908e..b1e7865 100644
--- a/core/net6.0/proxy/Apache.OpenWhisk.Runtime.Common/Apache.OpenWhisk.Runtime.Common.csproj
+++ b/core/net6.0/proxy/Apache.OpenWhisk.Runtime.Common/Apache.OpenWhisk.Runtime.Common.csproj
@@ -18,6 +18,7 @@
net6.0
+ enable
diff --git a/core/net6.0/proxy/Apache.OpenWhisk.Runtime.Common/Init.cs b/core/net6.0/proxy/Apache.OpenWhisk.Runtime.Common/Init.cs
index 0a1a054..1f25850 100644
--- a/core/net6.0/proxy/Apache.OpenWhisk.Runtime.Common/Init.cs
+++ b/core/net6.0/proxy/Apache.OpenWhisk.Runtime.Common/Init.cs
@@ -32,9 +32,9 @@ 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; }
+ private Type? Type { get; set; }
+ private MethodInfo? Method { get; set; }
+ private ConstructorInfo? Constructor { get; set; }
private bool AwaitableMethod { get; set; }
public Init()
@@ -45,7 +45,7 @@ public Init()
Constructor = null;
}
- public async Task HandleRequest(HttpContext httpContext)
+ public async Task HandleRequest(HttpContext httpContext)
{
await _initSemaphoreSlim.WaitAsync();
try
@@ -54,47 +54,46 @@ public async Task HandleRequest(HttpContext httpContext)
{
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, AwaitableMethod));
+ return new Run(Type, Method, Constructor, AwaitableMethod);
}
string body = await new StreamReader(httpContext.Request.Body).ReadToEndAsync();
JObject inputObject = JObject.Parse(body);
- if (!inputObject.ContainsKey("value"))
+ JToken? message;
+ if (!inputObject.TryGetValue("value", out message) || message is not JObject)
{
await httpContext.Response.WriteError("Missing main/no code to execute.");
- return (null);
+ return null;
}
- JToken message = inputObject["value"];
+ JObject valueObj = (JObject)message;
+ string main = valueObj.TryGetValue("main", out var mainToken) ? mainToken.ToString() : string.Empty;
+ string code = valueObj.TryGetValue("code", out var codeToken) ? codeToken.ToString() : string.Empty;
+ bool binary = valueObj.TryGetValue("binary", out var binaryToken) && binaryToken.ToObject();
- if (message["main"] == null || message["binary"] == null || message["code"] == null)
+ if (string.IsNullOrWhiteSpace(main) || string.IsNullOrWhiteSpace(code))
{
await httpContext.Response.WriteError("Missing main/no code to execute.");
- return (null);
+ return null;
}
- string main = message["main"].ToString();
-
- bool binary = message["binary"].ToObject();
-
if (!binary)
{
await httpContext.Response.WriteError("code must be binary (zip file).");
- return (null);
+ return null;
}
string[] mainParts = main.Split("::");
if (mainParts.Length != 3)
{
await httpContext.Response.WriteError("main required format is \"Assembly::Type::Function\".");
- return (null);
+ return null;
}
string tempPath = Path.Combine(Environment.CurrentDirectory, Guid.NewGuid().ToString());
- string base64Zip = message["code"].ToString();
try
{
- using (MemoryStream stream = new MemoryStream(Convert.FromBase64String(base64Zip)))
+ using (MemoryStream stream = new MemoryStream(Convert.FromBase64String(code)))
{
using (ZipArchive archive = new ZipArchive(stream))
{
@@ -105,7 +104,7 @@ public async Task HandleRequest(HttpContext httpContext)
catch (Exception)
{
await httpContext.Response.WriteError("Unable to decompress package.");
- return (null);
+ return null;
}
Environment.CurrentDirectory = tempPath;
@@ -117,19 +116,22 @@ public async Task HandleRequest(HttpContext httpContext)
if (!File.Exists(assemblyPath))
{
await httpContext.Response.WriteError($"Unable to locate requested assembly (\"{assemblyFile}\").");
- return (null);
+ return null;
}
try
{
+ JToken? envToken = valueObj["env"];
// Export init arguments as environment variables
- if (message["env"] != null && message["env"].HasValues)
+ if (envToken?.HasValues ?? false)
{
- Dictionary dictEnv = message["env"].ToObject>();
- foreach (KeyValuePair entry in dictEnv) {
- // See https://docs.microsoft.com/en-us/dotnet/api/system.environment.setenvironmentvariable
- // If entry.Value is null or the empty string, the variable is not set
- Environment.SetEnvironmentVariable(entry.Key, entry.Value);
+ var dictEnv = envToken.ToObject>();
+ if (dictEnv != null) {
+ foreach (var (key, value) in dictEnv) {
+ // See https://docs.microsoft.com/en-us/dotnet/api/system.environment.setenvironmentvariable
+ // If entry.Value is null or the empty string, the variable is not set
+ Environment.SetEnvironmentVariable(key, value);
+ }
}
}
@@ -138,7 +140,7 @@ public async Task HandleRequest(HttpContext httpContext)
if (Type == null)
{
await httpContext.Response.WriteError($"Unable to locate requested type (\"{mainParts[1]}\").");
- return (null);
+ return null;
}
Method = Type.GetMethod(mainParts[2]);
Constructor = Type.GetConstructor(Type.EmptyTypes);
@@ -151,26 +153,26 @@ await httpContext.Response.WriteError(ex.Message
+ ", " + ex.StackTrace
#endif
);
- return (null);
+ return null;
}
if (Method == null)
{
await httpContext.Response.WriteError($"Unable to locate requested method (\"{mainParts[2]}\").");
- return (null);
+ return null;
}
if (Constructor == null)
{
await httpContext.Response.WriteError($"Unable to locate appropriate constructor for (\"{mainParts[1]}\").");
- return (null);
+ return null;
}
Initialized = true;
- AwaitableMethod = (Method.ReturnType.GetMethod(nameof(Task.GetAwaiter)) != null);
+ AwaitableMethod = Method.ReturnType.GetMethod(nameof(Task.GetAwaiter)) != null;
- return (new Run(Type, Method, Constructor, AwaitableMethod));
+ return new Run(Type, Method, Constructor, AwaitableMethod);
}
catch (Exception ex)
{
@@ -181,7 +183,7 @@ await httpContext.Response.WriteError(ex.Message
#endif
);
Startup.WriteLogMarkers();
- return (null);
+ return null;
}
finally
{
diff --git a/core/net6.0/proxy/Apache.OpenWhisk.Runtime.Common/Run.cs b/core/net6.0/proxy/Apache.OpenWhisk.Runtime.Common/Run.cs
index 0ee99ce..91edd3f 100644
--- a/core/net6.0/proxy/Apache.OpenWhisk.Runtime.Common/Run.cs
+++ b/core/net6.0/proxy/Apache.OpenWhisk.Runtime.Common/Run.cs
@@ -26,12 +26,12 @@ namespace Apache.OpenWhisk.Runtime.Common
{
public class Run
{
- private readonly Type _type;
- private readonly MethodInfo _method;
- private readonly ConstructorInfo _constructor;
+ private readonly Type? _type;
+ private readonly MethodInfo? _method;
+ private readonly ConstructorInfo? _constructor;
private readonly bool _awaitableMethod;
- public Run(Type type, MethodInfo method, ConstructorInfo constructor, bool awaitableMethod)
+ public Run(Type? type, MethodInfo? method, ConstructorInfo? constructor, bool awaitableMethod)
{
_type = type;
_method = method;
@@ -51,10 +51,10 @@ public async Task HandleRequest(HttpContext httpContext)
{
string body = await new StreamReader(httpContext.Request.Body).ReadToEndAsync();
- JObject inputObject = string.IsNullOrEmpty(body) ? null : JObject.Parse(body);
+ JObject? inputObject = string.IsNullOrEmpty(body) ? null : JObject.Parse(body);
- JObject valObject = null;
- JArray valArray = null;
+ JObject? valObject = null;
+ JArray? valArray = null;
if (inputObject != null)
{
@@ -66,7 +66,7 @@ public async Task HandleRequest(HttpContext httpContext)
if (token.Path.Equals("value", StringComparison.InvariantCultureIgnoreCase))
continue;
string envKey = $"__OW_{token.Path.ToUpperInvariant()}";
- string envVal = token.First.ToString();
+ string? envVal = token.First?.ToString();
Environment.SetEnvironmentVariable(envKey, envVal);
//Console.WriteLine($"Set environment variable \"{envKey}\" to \"{envVal}\".");
}
@@ -85,20 +85,20 @@ await Console.Error.WriteLineAsync(
try
{
- JContainer output;
+ JContainer? output;
if(_awaitableMethod) {
if (valObject != null) {
- output = (JContainer) await (dynamic) _method.Invoke(owObject, new object[] {valObject});
+ output = (JContainer?) await (dynamic?) _method.Invoke(owObject, new object?[] {valObject});
} else {
- output = (JContainer) await (dynamic) _method.Invoke(owObject, new object[] {valArray});
+ output = (JContainer?) await (dynamic?) _method.Invoke(owObject, new object?[] {valArray});
}
}
else {
if (valObject != null) {
- output = (JContainer) _method.Invoke(owObject, new object[] {valObject});
+ output = (JContainer?) _method.Invoke(owObject, new object?[] {valObject});
} else {
- output = (JContainer) _method.Invoke(owObject, new object[] {valArray});
+ output = (JContainer?) _method.Invoke(owObject, new object?[] {valArray});
}
}
diff --git a/core/net6.0/proxy/Apache.OpenWhisk.Runtime.Common/Startup.cs b/core/net6.0/proxy/Apache.OpenWhisk.Runtime.Common/Startup.cs
index 9851e54..e8848bb 100644
--- a/core/net6.0/proxy/Apache.OpenWhisk.Runtime.Common/Startup.cs
+++ b/core/net6.0/proxy/Apache.OpenWhisk.Runtime.Common/Startup.cs
@@ -31,10 +31,10 @@ public static void WriteLogMarkers()
public void Configure(IApplicationBuilder app)
{
- PathString initPath = new PathString("/init");
- PathString runPath = new PathString("/run");
- Init init = new Init();
- Run run = null;
+ PathString initPath = new("/init");
+ PathString runPath = new("/run");
+ Init init = new();
+ Run? run = null;
app.Run(async (httpContext) =>
{
if (httpContext.Request.Path.Equals(initPath))
diff --git a/core/net6.0/proxy/Apache.OpenWhisk.Runtime.Dotnet.Minimal/Apache.OpenWhisk.Runtime.Dotnet.Minimal.csproj b/core/net6.0/proxy/Apache.OpenWhisk.Runtime.Dotnet.Minimal/Apache.OpenWhisk.Runtime.Dotnet.Minimal.csproj
index 1bcbb35..49af8c7 100644
--- a/core/net6.0/proxy/Apache.OpenWhisk.Runtime.Dotnet.Minimal/Apache.OpenWhisk.Runtime.Dotnet.Minimal.csproj
+++ b/core/net6.0/proxy/Apache.OpenWhisk.Runtime.Dotnet.Minimal/Apache.OpenWhisk.Runtime.Dotnet.Minimal.csproj
@@ -19,6 +19,7 @@
Exe
net6.0
+ enable
From cd42126d87cf4262bc845e8802e6b117bed2ed34 Mon Sep 17 00:00:00 2001
From: Guillermo Leon <18090460+gleono@users.noreply.github.com>
Date: Sat, 28 Sep 2024 14:48:20 -0500
Subject: [PATCH 2/5] Improve setting env variables on init
---
.../Apache.OpenWhisk.Runtime.Common/Init.cs | 21 +++++++------------
1 file changed, 8 insertions(+), 13 deletions(-)
diff --git a/core/net6.0/proxy/Apache.OpenWhisk.Runtime.Common/Init.cs b/core/net6.0/proxy/Apache.OpenWhisk.Runtime.Common/Init.cs
index 1f25850..c7cf5be 100644
--- a/core/net6.0/proxy/Apache.OpenWhisk.Runtime.Common/Init.cs
+++ b/core/net6.0/proxy/Apache.OpenWhisk.Runtime.Common/Init.cs
@@ -21,7 +21,6 @@
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
-using System.Collections.Generic;
using Microsoft.AspNetCore.Http;
using Newtonsoft.Json.Linq;
@@ -67,9 +66,9 @@ public Init()
}
JObject valueObj = (JObject)message;
- string main = valueObj.TryGetValue("main", out var mainToken) ? mainToken.ToString() : string.Empty;
- string code = valueObj.TryGetValue("code", out var codeToken) ? codeToken.ToString() : string.Empty;
- bool binary = valueObj.TryGetValue("binary", out var binaryToken) && binaryToken.ToObject();
+ string main = valueObj.TryGetValue("main", out JToken? mainToken) ? mainToken.ToString() : string.Empty;
+ string code = valueObj.TryGetValue("code", out JToken? codeToken) ? codeToken.ToString() : string.Empty;
+ bool binary = valueObj.TryGetValue("binary", out JToken? binaryToken) && binaryToken.ToObject();
if (string.IsNullOrWhiteSpace(main) || string.IsNullOrWhiteSpace(code))
{
@@ -121,17 +120,13 @@ public Init()
try
{
- JToken? envToken = valueObj["env"];
// Export init arguments as environment variables
- if (envToken?.HasValues ?? false)
+ if (valueObj.TryGetValue("env", out JToken? value) && value is JObject dictEnv)
{
- var dictEnv = envToken.ToObject>();
- if (dictEnv != null) {
- foreach (var (key, value) in dictEnv) {
- // See https://docs.microsoft.com/en-us/dotnet/api/system.environment.setenvironmentvariable
- // If entry.Value is null or the empty string, the variable is not set
- Environment.SetEnvironmentVariable(key, value);
- }
+ foreach ((string key, JToken? varValue) in dictEnv) {
+ // See https://docs.microsoft.com/en-us/dotnet/api/system.environment.setenvironmentvariable
+ // If entry.Value is null or the empty string, the variable is not set
+ Environment.SetEnvironmentVariable(key, varValue?.ToString());
}
}
From 08316bc293fa2ee9972e4b3d8f3f7f7bb53baf58 Mon Sep 17 00:00:00 2001
From: Guillermo Leon <18090460+gleono@users.noreply.github.com>
Date: Fri, 4 Oct 2024 13:48:13 -0500
Subject: [PATCH 3/5] Suggestion
---
core/net6.0/proxy/Apache.OpenWhisk.Runtime.Common/Init.cs | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/core/net6.0/proxy/Apache.OpenWhisk.Runtime.Common/Init.cs b/core/net6.0/proxy/Apache.OpenWhisk.Runtime.Common/Init.cs
index c7cf5be..24012fe 100644
--- a/core/net6.0/proxy/Apache.OpenWhisk.Runtime.Common/Init.cs
+++ b/core/net6.0/proxy/Apache.OpenWhisk.Runtime.Common/Init.cs
@@ -58,8 +58,7 @@ public Init()
string body = await new StreamReader(httpContext.Request.Body).ReadToEndAsync();
JObject inputObject = JObject.Parse(body);
- JToken? message;
- if (!inputObject.TryGetValue("value", out message) || message is not JObject)
+ if (!inputObject.TryGetValue("value", out JToken? message) || message is not JObject)
{
await httpContext.Response.WriteError("Missing main/no code to execute.");
return null;
From 745eecb44641644fffbed908f72e40dd6504316f Mon Sep 17 00:00:00 2001
From: Guillermo Leon <18090460+gleono@users.noreply.github.com>
Date: Mon, 7 Oct 2024 16:34:10 -0500
Subject: [PATCH 4/5] Small new features of C#
---
.../HttpResponseExtension.cs | 5 +-
.../Apache.OpenWhisk.Runtime.Common/Init.cs | 50 +++++++++----------
.../Apache.OpenWhisk.Runtime.Common/Run.cs | 5 +-
3 files changed, 28 insertions(+), 32 deletions(-)
diff --git a/core/net6.0/proxy/Apache.OpenWhisk.Runtime.Common/HttpResponseExtension.cs b/core/net6.0/proxy/Apache.OpenWhisk.Runtime.Common/HttpResponseExtension.cs
index 4f63bd0..8f97628 100644
--- a/core/net6.0/proxy/Apache.OpenWhisk.Runtime.Common/HttpResponseExtension.cs
+++ b/core/net6.0/proxy/Apache.OpenWhisk.Runtime.Common/HttpResponseExtension.cs
@@ -27,15 +27,14 @@ public static class HttpResponseExtension
{
public static async Task WriteResponse(this HttpResponse response, int code, string content)
{
- byte[] bytes = Encoding.UTF8.GetBytes(content);
- response.ContentLength = bytes.Length;
+ response.ContentLength = Encoding.UTF8.GetByteCount(content);
response.StatusCode = code;
await response.WriteAsync(content);
}
public static async Task WriteError(this HttpResponse response, string errorMessage)
{
- JObject message = new JObject {{"error", new JValue(errorMessage)}};
+ JObject message = new() {{"error", new JValue(errorMessage)}};
await WriteResponse(response, 502, JsonConvert.SerializeObject(message));
}
diff --git a/core/net6.0/proxy/Apache.OpenWhisk.Runtime.Common/Init.cs b/core/net6.0/proxy/Apache.OpenWhisk.Runtime.Common/Init.cs
index 24012fe..fbd7628 100644
--- a/core/net6.0/proxy/Apache.OpenWhisk.Runtime.Common/Init.cs
+++ b/core/net6.0/proxy/Apache.OpenWhisk.Runtime.Common/Init.cs
@@ -28,20 +28,20 @@ namespace Apache.OpenWhisk.Runtime.Common
{
public class Init
{
- private readonly SemaphoreSlim _initSemaphoreSlim = new SemaphoreSlim(1, 1);
+ private readonly SemaphoreSlim _initSemaphoreSlim = new(initialCount: 1, maxCount: 1);
+ private Type? _type;
+ private MethodInfo? _method;
+ private ConstructorInfo? _constructor;
+ private bool _awaitableMethod;
public bool Initialized { get; private set; }
- private Type? Type { get; set; }
- private MethodInfo? Method { get; set; }
- private ConstructorInfo? Constructor { get; set; }
- private bool AwaitableMethod { get; set; }
public Init()
{
Initialized = false;
- Type = null;
- Method = null;
- Constructor = null;
+ _type = null;
+ _method = null;
+ _constructor = null;
}
public async Task HandleRequest(HttpContext httpContext)
@@ -53,18 +53,18 @@ public Init()
{
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, AwaitableMethod);
+ return new Run(_type, _method, _constructor, _awaitableMethod);
}
- string body = await new StreamReader(httpContext.Request.Body).ReadToEndAsync();
+ using StreamReader reader = new(httpContext.Request.Body);
+ string body = await reader.ReadToEndAsync();
JObject inputObject = JObject.Parse(body);
- if (!inputObject.TryGetValue("value", out JToken? message) || message is not JObject)
+ if (!inputObject.TryGetValue("value", out JToken? message) || message is not JObject valueObj)
{
await httpContext.Response.WriteError("Missing main/no code to execute.");
return null;
}
- JObject valueObj = (JObject)message;
string main = valueObj.TryGetValue("main", out JToken? mainToken) ? mainToken.ToString() : string.Empty;
string code = valueObj.TryGetValue("code", out JToken? codeToken) ? codeToken.ToString() : string.Empty;
bool binary = valueObj.TryGetValue("binary", out JToken? binaryToken) && binaryToken.ToObject();
@@ -91,13 +91,9 @@ public Init()
string tempPath = Path.Combine(Environment.CurrentDirectory, Guid.NewGuid().ToString());
try
{
- using (MemoryStream stream = new MemoryStream(Convert.FromBase64String(code)))
- {
- using (ZipArchive archive = new ZipArchive(stream))
- {
- archive.ExtractToDirectory(tempPath);
- }
- }
+ using MemoryStream stream = new(Convert.FromBase64String(code));
+ using ZipArchive archive = new(stream);
+ archive.ExtractToDirectory(tempPath);
}
catch (Exception)
{
@@ -130,14 +126,14 @@ public Init()
}
Assembly assembly = Assembly.LoadFrom(assemblyPath);
- Type = assembly.GetType(mainParts[1]);
- if (Type == null)
+ _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);
+ _method = _type.GetMethod(mainParts[2]);
+ _constructor = _type.GetConstructor(Type.EmptyTypes);
}
catch (Exception ex)
{
@@ -150,13 +146,13 @@ await httpContext.Response.WriteError(ex.Message
return null;
}
- if (Method == null)
+ if (_method == null)
{
await httpContext.Response.WriteError($"Unable to locate requested method (\"{mainParts[2]}\").");
return null;
}
- if (Constructor == null)
+ if (_constructor == null)
{
await httpContext.Response.WriteError($"Unable to locate appropriate constructor for (\"{mainParts[1]}\").");
return null;
@@ -164,9 +160,9 @@ await httpContext.Response.WriteError(ex.Message
Initialized = true;
- AwaitableMethod = Method.ReturnType.GetMethod(nameof(Task.GetAwaiter)) != null;
+ _awaitableMethod = _method.ReturnType.GetMethod(nameof(Task.GetAwaiter)) != null;
- return new Run(Type, Method, Constructor, AwaitableMethod);
+ return new Run(_type, _method, _constructor, _awaitableMethod);
}
catch (Exception ex)
{
diff --git a/core/net6.0/proxy/Apache.OpenWhisk.Runtime.Common/Run.cs b/core/net6.0/proxy/Apache.OpenWhisk.Runtime.Common/Run.cs
index 91edd3f..13e1eeb 100644
--- a/core/net6.0/proxy/Apache.OpenWhisk.Runtime.Common/Run.cs
+++ b/core/net6.0/proxy/Apache.OpenWhisk.Runtime.Common/Run.cs
@@ -49,7 +49,8 @@ public async Task HandleRequest(HttpContext httpContext)
try
{
- string body = await new StreamReader(httpContext.Request.Body).ReadToEndAsync();
+ using StreamReader reader = new(httpContext.Request.Body);
+ string body = await reader.ReadToEndAsync();
JObject? inputObject = string.IsNullOrEmpty(body) ? null : JObject.Parse(body);
@@ -81,7 +82,7 @@ await Console.Error.WriteLineAsync(
}
}
- object owObject = _constructor.Invoke(new object[] { });
+ object owObject = _constructor.Invoke(Array.Empty