diff --git a/dotnet60/Common/BuilderSettings.cs b/dotnet60/Common/BuilderSettings.cs
new file mode 100644
index 00000000..69589c42
--- /dev/null
+++ b/dotnet60/Common/BuilderSettings.cs
@@ -0,0 +1,18 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Fission.Common
+{
+ public readonly record struct BuilderSettings(
+ string NugetSpecsFile,
+ string DllExcludeFile,
+ string BuildLogDirectory,
+ string NugetPackageRegEx,
+ string ExcludeDllRegEx,
+ bool RunningOnWindows,
+ string functionBodyFileName,
+ string functionSpecFileName,
+ string DllDirectory
+ );
+}
diff --git a/dotnet60/Common/Common.csproj b/dotnet60/Common/Common.csproj
new file mode 100644
index 00000000..30313518
--- /dev/null
+++ b/dotnet60/Common/Common.csproj
@@ -0,0 +1,12 @@
+
+
+
+ net6.0
+ true
+
+
+
+
+
+
+
diff --git a/dotnet60/Common/CompilerHelper.cs b/dotnet60/Common/CompilerHelper.cs
new file mode 100644
index 00000000..1856c06c
--- /dev/null
+++ b/dotnet60/Common/CompilerHelper.cs
@@ -0,0 +1,112 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+using System.Text.RegularExpressions;
+using System.Text.Json;
+using System.Linq;
+
+namespace Fission.Common
+{
+
+ public sealed class CompilerHelper
+ {
+
+ private static readonly Lazy lazy =
+ new Lazy(() => new CompilerHelper());
+
+ public string _logFileName = string.Empty;
+ public static CompilerHelper Instance { get { return lazy.Value; } }
+
+ private BuilderSettings? _builderSettings = null;
+
+ public BuilderSettings builderSettings
+ {
+ get
+ {
+ if (_builderSettings == null)
+ {
+ string builderSettingsjson = GetBuilderSettingsJson();
+ _builderSettings = JsonSerializer.Deserialize(builderSettingsjson);
+ }
+
+ return _builderSettings.Value;
+ }
+ set
+ {
+ builderSettings = value;
+ }
+ }
+
+ static CompilerHelper()
+ {
+ }
+
+ private CompilerHelper()
+ {
+ }
+
+ public static string GetRelevantPathAsPerOS(string currentPath)
+ {
+ if (CompilerHelper.Instance.builderSettings.RunningOnWindows)
+ {
+ return currentPath;
+ }
+ else
+ {
+ return currentPath.Replace("\\","/");
+ }
+ }
+
+ private string GetBuilderSettingsJson()
+ {
+ var path = AppDomain.CurrentDomain.BaseDirectory + "builderSettings.json";
+ return System.IO.File.ReadAllText(path);
+ }
+
+ public FunctionSpecification GetFunctionSpecs(string directoryPath)
+ {
+ string functionSpecsFilePath = Path.Combine(directoryPath, this.builderSettings.functionSpecFileName);
+ if (!File.Exists(functionSpecsFilePath))
+ {
+ string specsJson = File.ReadAllText(functionSpecsFilePath);
+ return JsonSerializer.Deserialize(specsJson);
+ }
+
+ throw new Exception($"Function Specification file not found at {functionSpecsFilePath}");
+ }
+
+ public static IEnumerable GetDirectoryFiles(string rootPath, string patternMatch, SearchOption searchOption)
+ {
+ var foundFiles = Enumerable.Empty();
+
+ if (searchOption == SearchOption.AllDirectories)
+ {
+ try
+ {
+ IEnumerable subDirs = Directory.EnumerateDirectories(rootPath);
+ foreach (string dir in subDirs)
+ {
+ foundFiles = foundFiles.Concat(GetDirectoryFiles(dir, patternMatch, searchOption)); // Add files in subdirectories recursively to the list
+ }
+ }
+ catch (UnauthorizedAccessException) {}
+ catch (PathTooLongException) {}
+ }
+
+ try
+ {
+ foundFiles = foundFiles.Concat(Directory.EnumerateFiles(rootPath, patternMatch)); // Add files from the current directory
+ }
+ catch (UnauthorizedAccessException) {}
+
+ return foundFiles;
+ }
+
+ static public IEnumerable GetCSharpSources(string path)
+ {
+ return GetDirectoryFiles(path, "*.cs", SearchOption.AllDirectories);
+ }
+ }
+
+}
diff --git a/dotnet60/Common/DllInfo.cs b/dotnet60/Common/DllInfo.cs
new file mode 100644
index 00000000..4756c6c8
--- /dev/null
+++ b/dotnet60/Common/DllInfo.cs
@@ -0,0 +1,8 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Fission.Common
+{
+ public readonly record struct DllInfo(string name, string rootPackage, string framework, string processor, string path);
+}
diff --git a/dotnet60/Common/FunctionSpecification.cs b/dotnet60/Common/FunctionSpecification.cs
new file mode 100644
index 00000000..d48848ca
--- /dev/null
+++ b/dotnet60/Common/FunctionSpecification.cs
@@ -0,0 +1,17 @@
+using System.Collections.Generic;
+
+namespace Fission.Common
+{
+ public readonly record struct FunctionSpecification(
+ string functionName,
+ List libraries,
+ string hash,
+ string certificatePath
+ );
+
+ public readonly record struct Library(
+ string name,
+ string path,
+ string nugetPackage
+ );
+}
diff --git a/dotnet60/Dockerfile b/dotnet60/Dockerfile
new file mode 100644
index 00000000..b27d5efb
--- /dev/null
+++ b/dotnet60/Dockerfile
@@ -0,0 +1,18 @@
+# Prep work for all images.
+FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
+WORKDIR /app
+EXPOSE 8888
+
+FROM mcr.microsoft.com/dotnet/sdk:6.0 AS restore
+WORKDIR /src
+COPY . /src
+RUN dotnet restore "./fission-dotnet6.sln"
+
+# Specific work for environment image.
+FROM restore as build-env
+RUN dotnet publish "./fission-dotnet6/fission-dotnet6.csproj" -c Release -o /app/publish
+
+FROM base AS final
+WORKDIR /app
+COPY --from=build-env /app/publish .
+ENTRYPOINT ["dotnet", "fission-dotnet6.dll"]
diff --git a/dotnet60/Dockerfile.builder b/dotnet60/Dockerfile.builder
new file mode 100644
index 00000000..a91e2c73
--- /dev/null
+++ b/dotnet60/Dockerfile.builder
@@ -0,0 +1,39 @@
+ARG BUILDER_IMAGE=fission/builder
+FROM ${BUILDER_IMAGE} AS fission-builder
+
+
+FROM mcr.microsoft.com/dotnet/sdk:6.0 AS builderimage
+
+
+WORKDIR /app
+
+# Copy csproj and restore as distinct layers
+COPY Common ./../Common
+COPY Fission.Functions ./../Fission.Functions
+COPY builder/*.csproj ./
+RUN dotnet restore
+
+# Copy everything else and build
+COPY builder ./
+RUN dotnet publish -c Release -o out
+
+
+# Build runtime image
+FROM mcr.microsoft.com/dotnet/aspnet:6.0
+WORKDIR /app
+COPY --from=builderimage /app/out .
+
+# this builder is actually compilation from : https://github.com/fission/fission/tree/master/builder/cmd and renamed cmd.exe to builder
+# make sure to compile it in linux only else you will get exec execute error as binary was compiled in windows and running on linux
+
+COPY --from=fission-builder /builder /builder
+
+#ADD builder /builder
+
+ADD builder/build.sh /usr/local/bin/build
+RUN chmod +x /usr/local/bin/build
+
+ADD builder/build.sh /bin/build
+RUN chmod +x /bin/build
+
+EXPOSE 8001
\ No newline at end of file
diff --git a/dotnet60/Fission.Functions/Fission.Functions.csproj b/dotnet60/Fission.Functions/Fission.Functions.csproj
new file mode 100644
index 00000000..30313518
--- /dev/null
+++ b/dotnet60/Fission.Functions/Fission.Functions.csproj
@@ -0,0 +1,12 @@
+
+
+
+ net6.0
+ true
+
+
+
+
+
+
+
diff --git a/dotnet60/Fission.Functions/FissionContext.cs b/dotnet60/Fission.Functions/FissionContext.cs
new file mode 100644
index 00000000..72a8887a
--- /dev/null
+++ b/dotnet60/Fission.Functions/FissionContext.cs
@@ -0,0 +1,66 @@
+#region header
+
+// Fission.Functions - FissionContext.cs
+//
+// Created by: Alistair J R Young (avatar) at 2020/12/28 11:30 PM.
+
+#endregion
+
+#region using
+
+using System.Collections.Generic;
+using System.IO;
+using System.Text.Json;
+
+using JetBrains.Annotations;
+
+#endregion
+
+namespace Fission.Functions
+{
+ ///
+ /// The context supplied to Fission functions by the .NET 5 environment, including arguments, HTTP request information,
+ /// logging facilities, and (for built functions) settings.
+ ///
+ [PublicAPI]
+ public record FissionContext
+ {
+ ///
+ /// The arguments specified to the Fission function, derived from the HTTP request's query string.
+ ///
+ public IReadOnlyDictionary Arguments;
+
+ ///
+ /// Functions permitting the Fission function to write to the container log.
+ ///
+ public FissionLogger Logger;
+
+ ///
+ /// The path to the location in which the Fission function package is loaded into the container.
+ ///
+ ///
+ /// This is primarily used internally to fetch the location for JSON settings files.
+ ///
+ public string PackagePath;
+
+ ///
+ /// Details of the HTTP request which generated the function call.
+ ///
+ public FissionRequest Request;
+
+ ///
+ /// Read a JSON settings file supplied in the function package, and deserialize it into a corresponding .NET object.
+ ///
+ /// Type of the .NET object corresponding to the settings file.
+ /// Path, beneath , of the JSON settings file.
+ /// A .NET object corresponding to the JSON settings file.
+ [CanBeNull]
+ public T GetSettings ([NotNull] string relativePath)
+ {
+ string filePath = Path.Combine (path1: this.PackagePath, path2: relativePath);
+ string json = File.ReadAllText (path: filePath);
+
+ return JsonSerializer.Deserialize (json: json);
+ }
+ }
+}
diff --git a/dotnet60/Fission.Functions/FissionLogger.cs b/dotnet60/Fission.Functions/FissionLogger.cs
new file mode 100644
index 00000000..452ae10e
--- /dev/null
+++ b/dotnet60/Fission.Functions/FissionLogger.cs
@@ -0,0 +1,51 @@
+#region header
+
+// Fission.Functions - FissionLogger.cs
+//
+// Created by: Alistair J R Young (avatar) at 2020/12/30 8:08 AM.
+
+#endregion
+
+#region using
+
+using JetBrains.Annotations;
+
+#endregion
+
+namespace Fission.Functions
+{
+ ///
+ /// A delegate defining a function capable of performing Fission function logging; i.e., a possible FissionLogger
+ /// function.
+ ///
+ /// The message to log, in the form of a format string for the following arguments, if any.
+ /// Any arguments to log (parameters for the format string).
+ public delegate void FissionWriteLog (string format, params object[] args);
+
+ ///
+ /// Logging functions for the receiving Fission function.
+ ///
+ [PublicAPI]
+ public record FissionLogger
+ {
+ ///
+ /// Log a message reporting a critical error.
+ ///
+ public FissionWriteLog WriteCritical;
+
+ ///
+ /// Log a message reporting an error.
+ ///
+ public FissionWriteLog WriteError;
+
+ ///
+ /// Log an informational message.
+ ///
+ public FissionWriteLog WriteInfo;
+
+ ///
+ /// Log a warning message.
+ ///
+ public FissionWriteLog WriteWarning;
+ }
+}
diff --git a/dotnet60/Fission.Functions/FissionRequest.cs b/dotnet60/Fission.Functions/FissionRequest.cs
new file mode 100644
index 00000000..5bde9ac7
--- /dev/null
+++ b/dotnet60/Fission.Functions/FissionRequest.cs
@@ -0,0 +1,73 @@
+#region header
+
+// Fission.Functions - FissionRequest.cs
+//
+// Created by: Alistair J R Young (avatar) at 2020/12/30 8:08 AM.
+
+#endregion
+
+#region using
+
+using System.Collections.Generic;
+using System.IO;
+using System.Security.Cryptography.X509Certificates;
+using System.Text;
+
+using JetBrains.Annotations;
+
+#endregion
+
+namespace Fission.Functions
+{
+ ///
+ /// Underlying request details supplied to the handling function.
+ ///
+ [PublicAPI]
+ public record FissionRequest
+ {
+ ///
+ /// The body of the request, supplied as a readable . See also
+ /// to receive the entire body of the request as a single
+ /// .
+ ///
+ public Stream Body;
+
+ ///
+ /// The client certificate supplied with the request.
+ ///
+ [CanBeNull]
+ public X509Certificate2 ClientCertificate;
+
+ ///
+ /// The HTTP headers supplied with the request.
+ ///
+ public IReadOnlyDictionary> Headers;
+
+ ///
+ /// The HTTP method used to make the request (i.e., "GET", "POST", etc.).
+ ///
+ public string Method;
+
+ ///
+ /// The URL used to make the request, formatted as a string.
+ ///
+ ///
+ /// The URL is urlencoded, and includes all elements, including (for example) the query string.
+ ///
+ public string Url;
+
+ ///
+ /// Get the body of the request as a single .
+ ///
+ /// The body of the request as a single .
+ [NotNull]
+ public string GetBodyAsString ()
+ {
+ var length = (int) this.Body.Length;
+ var data = new byte[length];
+ this.Body.Read (buffer: data, offset: 0, count: length);
+
+ return Encoding.UTF8.GetString (bytes: data);
+ }
+ }
+}
diff --git a/dotnet60/Fission.Functions/IFissionFunction.cs b/dotnet60/Fission.Functions/IFissionFunction.cs
new file mode 100644
index 00000000..3318d768
--- /dev/null
+++ b/dotnet60/Fission.Functions/IFissionFunction.cs
@@ -0,0 +1,35 @@
+#region header
+
+// Fission.Functions - IFissionFunction.cs
+//
+// Created by: Alistair J R Young (avatar) at 2020/12/28 11:29 PM.
+
+#endregion
+
+#region using
+
+using JetBrains.Annotations;
+
+#endregion
+
+namespace Fission.Functions
+{
+ ///
+ /// The interface which is implemented by Fission functions, permitting the environment container to identify possible
+ /// entry
+ /// points.
+ ///
+ [PublicAPI]
+ public interface IFissionFunction
+ {
+ ///
+ /// The entry point of a Fission function.
+ ///
+ /// The function call context supplied by the environment container.
+ ///
+ /// An object which will be appropriately formatted by the environment container and returned to the
+ /// caller.
+ ///
+ public object Execute (FissionContext context);
+ }
+}
diff --git a/dotnet60/LICENSE b/dotnet60/LICENSE
new file mode 100644
index 00000000..66a27ec5
--- /dev/null
+++ b/dotnet60/LICENSE
@@ -0,0 +1,177 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
diff --git a/dotnet60/README.md b/dotnet60/README.md
new file mode 100644
index 00000000..e4e3f54a
--- /dev/null
+++ b/dotnet60/README.md
@@ -0,0 +1,53 @@
+# fission-dotnet6
+A .NET 6 function environment for [Fission](https://fission.io/).
+
+The environment Docker image (_fission-dotnet6_) contains the .NET 6.0 runtime and uses an ASP.NET Core web api application to make the relevant endpoints available to Fission. This image supports compiling and running single-file functions using the types available in the core .NET 6 assemblies. To use multi-file projects and download packages with NuGet, use builder image in it's directory.
+
+The environment works via the IFissionFunction interface (provided by the _Fission.Functions_ assembly.) A function for _fission-dotnet6_ is presented as a class which implements the _IFissionFunction_ interface, thus:
+
+```
+using System;
+using Fission.Functions;
+
+public class HelloWorld : IFissionFunction
+{
+ public object Execute(FissionContext context)
+ {
+ return "hello, world!";
+ }
+}
+
+```
+
+Logging and access to function call parameters are accessible through the _context_ parameter. Please see the inline documentation for _FissionContext.cs_ and the examples for further details.
+
+## Rebuilding the image
+
+To rebuild the containers, in the top-level directory, execute the following:
+
+```
+docker build . --platform=linux/amd64,linux/arm64,linux/arm -t repository/fission-dotnet6:dev --push
+```
+
+## Setting up the Fission environment
+
+To set up the .NET 6 Fission environment, execute the command:
+
+```
+fission env create --name dotnet6 --image repository/fission-dotnet6:dev --version 1
+```
+
+## Configuring and testing a function
+
+If the above function is contained within the file `HelloWorld.cs` (see the examples directory), and the environment has been set up as above, then it can be installed as follows:
+
+```
+fission fn create --name hello-dotnet --env dotnet6 --code HelloWorld.cs
+```
+
+And tested thus:
+
+```
+fission fn test --name hello-dotnet
+```
+
diff --git a/dotnet60/builder/Builder.cs b/dotnet60/builder/Builder.cs
new file mode 100644
index 00000000..e60b8f35
--- /dev/null
+++ b/dotnet60/builder/Builder.cs
@@ -0,0 +1,51 @@
+using Builder.Utility;
+using NugetWorker;
+using System;
+using System.IO;
+using Builder.Engine;
+using Fission.Common;
+
+namespace Builder
+{
+ class Builder
+ {
+ static void Main(string[] args)
+ {
+ Console.WriteLine("Starting builder task");
+ var logFileName = $"{DateTime.Now.ToString("yyyy_MM_dd")}_{Guid.NewGuid().ToString()}.log";
+
+ try
+ {
+ string _logdirectory = CompilerHelper.Instance.builderSettings.BuildLogDirectory;
+ BuilderHelper.Instance._logFileName = Path.Combine(_logdirectory, logFileName);
+ BuilderHelper.Instance.logger = new Utility.Logger(
+ BuilderHelper.Instance._logFileName);
+
+ NugetHelper.Instance.logger = new NugetWorker.Logger(BuilderHelper.Instance._logFileName);
+
+ Console.WriteLine($"detailed logs for this build will be at: {Path.Combine(_logdirectory, logFileName)}");
+
+
+ BuilderEngine builderEngine = new BuilderEngine();
+ builderEngine.BuildPackage().Wait();
+ }
+ catch (Exception ex)
+ {
+ string detailedException = string.Empty;
+ try
+ {
+ detailedException= BuilderHelper.Instance.DeepException(ex);
+ Console.WriteLine($"Exception during build: {Environment.NewLine} {ex.Message} | {ex.StackTrace} | {Environment.NewLine} {detailedException}");
+ }
+ catch(Exception childEx)
+ {
+ Console.WriteLine($"{Environment.NewLine} Exception during build:{ex.Message} |{Environment.NewLine} {ex.StackTrace} {Environment.NewLine} ");
+ }
+
+ throw;
+ }
+
+ Console.WriteLine("Builder task done");
+ }
+ }
+}
diff --git a/dotnet60/builder/Builder.csproj b/dotnet60/builder/Builder.csproj
new file mode 100644
index 00000000..0f02d80d
--- /dev/null
+++ b/dotnet60/builder/Builder.csproj
@@ -0,0 +1,47 @@
+
+
+
+ Exe
+ net6.0
+
+
+
+
+
+
+
+
+
+
+
+
+ System
+
+
+
+
+
+
+
+
+
+
+
+
+ Always
+
+
+ Always
+
+
+ Always
+
+
+ Always
+
+
+ Always
+
+
+
+
diff --git a/dotnet60/builder/Builder.sln b/dotnet60/builder/Builder.sln
new file mode 100644
index 00000000..14f4184d
--- /dev/null
+++ b/dotnet60/builder/Builder.sln
@@ -0,0 +1,25 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 15
+VisualStudioVersion = 15.0.27906.1
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Builder", "Builder.csproj", "{D479FF57-44A0-483D-B5B0-B6C475D12292}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {D479FF57-44A0-483D-B5B0-B6C475D12292}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {D479FF57-44A0-483D-B5B0-B6C475D12292}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {D479FF57-44A0-483D-B5B0-B6C475D12292}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {D479FF57-44A0-483D-B5B0-B6C475D12292}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {AA20D0B8-E5D5-4BA1-9E29-FC5132A4DD00}
+ EndGlobalSection
+EndGlobal
diff --git a/dotnet60/builder/BuilderEngine/BuilderEngine.cs b/dotnet60/builder/BuilderEngine/BuilderEngine.cs
new file mode 100644
index 00000000..7bfcd576
--- /dev/null
+++ b/dotnet60/builder/BuilderEngine/BuilderEngine.cs
@@ -0,0 +1,247 @@
+using Builder.Model;
+using Builder.Utility;
+using NugetWorker;
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading.Tasks;
+using System.Linq;
+using NuGet.Packaging;
+using System.IO;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp;
+using System.Reflection;
+using Microsoft.CodeAnalysis.Emit;
+using System.Runtime.Loader;
+using System.Text.Json;
+using Fission.Functions;
+using Fission.Common;
+
+namespace Builder.Engine
+{
+ public class BuilderEngine
+ {
+ public string SRC_PKG = string.Empty;
+
+ List dllInfos = new List();
+ List excludeDlls = new List();
+ List includeNugets = new List();
+ List compileErrors = new List();
+ List compileInfo = new List();
+
+ public BuilderEngine()
+ {
+ SRC_PKG = Environment.GetEnvironmentVariable("SRC_PKG");
+ }
+
+
+ public async Task BuildPackage()
+ {
+ await BuildDllInfo();
+
+ Console.WriteLine("Compiling");
+ bool compiled = await TryCompile();
+ if (compiled)
+ {
+ CopyToSourceDir();
+ await BuildSpecs();
+ Console.WriteLine("Compilation and building function specification done!");
+ }
+ else
+ {
+ Console.WriteLine("Compilation failed:");
+ foreach(var error in compileErrors)
+ {
+ Console.WriteLine($"COMPILATION ERROR: {error}");
+ }
+ throw new Exception($"COMPILATION FAILED! See builder logs for details, total errors: {compileErrors.Count}");
+
+ }
+
+ }
+
+ public void CopyToSourceDir()
+ {
+ // create folder if it doesn't already exist
+ string destinationFile = Path.Combine(SRC_PKG, CompilerHelper.Instance.builderSettings.DllDirectory, "dummy.txt");
+ new FileInfo(destinationFile).Directory.Create();
+
+ foreach (var dllinfo in dllInfos)
+ {
+ string filename = Path.GetFileName(dllinfo.path);
+ destinationFile = Path.Combine(SRC_PKG, CompilerHelper.Instance.builderSettings.DllDirectory, filename);
+ File.Copy(dllinfo.path, destinationFile,true);
+ }
+ }
+
+ public async Task TryCompile()
+ {
+ string codeFile = Path.Combine(SRC_PKG, CompilerHelper.Instance.builderSettings.functionBodyFileName);
+ if (!File.Exists(codeFile))
+ {
+ Console.WriteLine($"Source Code not found at : {codeFile} !" +
+ $" to use TryCompile() in Builder, make sure, your main function file name is " +
+ $"{CompilerHelper.Instance.builderSettings.functionBodyFileName} and " +
+ $"it is located at root of zip!" );
+ return false;
+ }
+ return await Compile();
+ }
+
+ public async Task Compile()
+ {
+ var syntaxTrees = new List();
+ var options = CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.Latest);
+
+ foreach (var codeInDirectory in CompilerHelper.GetCSharpSources(SRC_PKG))
+ {
+ syntaxTrees.Add(CSharpSyntaxTree.ParseText(File.ReadAllText(codeInDirectory), options));
+ }
+ string assemblyName = Path.GetRandomFileName();
+
+ var coreDir = Directory.GetParent(typeof(Enumerable).GetTypeInfo().Assembly.Location);
+
+ List references = new List
+ {
+ MetadataReference.CreateFromFile(coreDir.FullName + Path.DirectorySeparatorChar + "mscorlib.dll"),
+ MetadataReference.CreateFromFile(coreDir.FullName + Path.DirectorySeparatorChar + "netstandard.dll"),
+ MetadataReference.CreateFromFile(typeof(object).GetTypeInfo().Assembly.Location),
+ MetadataReference.CreateFromFile(Assembly.GetEntryAssembly().Location),
+ MetadataReference.CreateFromFile(typeof(System.Runtime.Serialization.Json.DataContractJsonSerializer).GetTypeInfo().Assembly.Location),
+ MetadataReference.CreateFromFile(path: typeof(IFissionFunction).GetTypeInfo().Assembly.Location),
+ };
+
+ foreach (var referencedAssembly in Assembly.GetEntryAssembly().GetReferencedAssemblies())
+ {
+ var assembly = Assembly.Load(referencedAssembly);
+ references.Add(MetadataReference.CreateFromFile(assembly.Location));
+ BuilderHelper.Instance.logger.Log($"Referring assembly-based dlls: {assembly.Location}");
+ }
+
+
+ AppDomain currentDomain = AppDomain.CurrentDomain;
+ currentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
+
+ foreach (var dll in dllInfos)
+ {
+ BuilderHelper.Instance.logger.Log($"Referring nuget-based dll: {dll.path}");
+ references.Add(MetadataReference.CreateFromFile(dll.path));
+ }
+
+ CSharpCompilation compilation = CSharpCompilation.Create(
+ assemblyName,
+ syntaxTrees: syntaxTrees.ToArray(),
+ references: references,
+ options: new CSharpCompilationOptions(
+ OutputKind.DynamicallyLinkedLibrary,
+ optimizationLevel: OptimizationLevel.Release));
+
+ var ms = new MemoryStream();
+ EmitResult result = compilation.Emit(ms);
+
+ if (!result.Success)
+ {
+ IEnumerable failures = result.Diagnostics.Where(diagnostic =>
+ diagnostic.IsWarningAsError ||
+ diagnostic.Severity == DiagnosticSeverity.Error).ToList();
+
+ foreach (Diagnostic diagnostic in failures)
+ {
+ compileErrors.Add($"{diagnostic.Id}: {diagnostic.GetMessage()}");
+ BuilderHelper.Instance.logger.Log($"COMPILE ERROR :{diagnostic.Id}: {diagnostic.GetMessage()}");
+ }
+ return false;
+ }
+
+ BuilderHelper.Instance.logger.Log("Compile success!",true);
+
+ return true;
+ }
+
+ public async Task BuildSpecs()
+ {
+ var functionName = CompilerHelper.Instance.builderSettings.functionBodyFileName;
+ var libraries = new List();
+
+ foreach (var dllinfo in dllInfos)
+ {
+ string combinedPath = Path.Combine(CompilerHelper.Instance.builderSettings.DllDirectory, Path.GetFileName(dllinfo.path));
+ string destinationFile = CompilerHelper.GetRelevantPathAsPerOS(combinedPath);
+
+ var library = new Library()
+ {
+ name = dllinfo.name,
+ nugetPackage = dllinfo.rootPackage,
+ path = destinationFile
+ };
+ libraries.Add(library);
+ }
+ var functionSpecification = new FunctionSpecification(functionName, libraries, "", "");
+ string funcMetaJson = JsonSerializer.Serialize(functionSpecification);
+ string funcMetaFile = Path.Combine(this.SRC_PKG, CompilerHelper.Instance.builderSettings.functionSpecFileName);
+ BuilderHelper.Instance.WriteToFile(funcMetaFile, funcMetaJson);
+ }
+
+ public async Task BuildDllInfo()
+ {
+ includeNugets = BuilderHelper.Instance.GetNugetToInclude(SRC_PKG);
+
+ foreach (var nuget in includeNugets)
+ {
+ NugetEngine nugetEngine = new NugetEngine();
+ await nugetEngine.GetPackage(nuget.packageName, nuget.version);
+ dllInfos.AddRange(nugetEngine.dllInfos);
+ }
+
+ dllInfos = System.Linq.Enumerable.DistinctBy(dllInfos, x => x.path).ToList();
+
+#if DEBUG
+ dllInfos.LogDllPathstoCSV("preFilter.CSV");
+#endif
+
+ excludeDlls = BuilderHelper.Instance.GetDllsToExclude(SRC_PKG);
+ foreach (var excludedll in excludeDlls)
+ {
+ BuilderHelper.Instance.logger.Log($"Trying to remove excluded dll, if available: {excludedll.dllName} from package {excludedll.packageName}");
+ dllInfos.RemoveAll(x => x.rootPackage.ToLower() == excludedll.packageName.ToLower() && x.name.ToLower() == excludedll.dllName.ToLower());
+ }
+
+#if DEBUG
+ dllInfos.LogDllPathstoCSV("PostFilter.CSV");
+#endif
+
+ }
+
+ private Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
+ {
+ // This handler is called only when the common language runtime tries to bind to the assembly and fails.
+
+ BuilderHelper.Instance.logger.Log($"Dynamically trying to load dll {(args.Name.Substring(0, args.Name.IndexOf(",")).ToString() + ".dll").ToLower()} in parent assembly");
+
+ // Retrieve the list of referenced assemblies in an array of AssemblyName.
+ Assembly MyAssembly = null, objExecutingAssemblies;
+ string assemblyPath = "";
+
+ objExecutingAssemblies = Assembly.GetExecutingAssembly();
+ AssemblyName[] referencedAssemblyNames = objExecutingAssemblies.GetReferencedAssemblies();
+
+ // Loop through the array of referenced assembly names.
+ if (dllInfos.Any(x => x.name.ToLower() == (args.Name.Substring(0, args.Name.IndexOf(",")).ToString() + ".dll").ToLower()))
+ {
+ assemblyPath = dllInfos.Where(x => x.name.ToLower() == (args.Name.Substring(0, args.Name.IndexOf(",")).ToString() + ".dll").ToLower()).FirstOrDefault().path;
+
+ BuilderHelper.Instance.logger.Log($"loading dll in parent assembly: {assemblyPath}");
+
+ MyAssembly = Assembly.LoadFile(assemblyPath);
+ }
+
+ if (MyAssembly == null)
+ {
+ BuilderHelper.Instance.logger.Log($"WARNING! Unable to locate dll: {(args.Name.Substring(0, args.Name.IndexOf(",")).ToString() + ".dll").ToLower()} ", true);
+ }
+
+ return MyAssembly;
+ }
+
+ }
+}
diff --git a/dotnet60/builder/Makefile b/dotnet60/builder/Makefile
new file mode 100644
index 00000000..19e33f18
--- /dev/null
+++ b/dotnet60/builder/Makefile
@@ -0,0 +1,8 @@
+PLATFORMS ?= linux/amd64
+
+-include ../../rules.mk
+
+.PHONY: all
+all: dotnet6-builder-img
+
+dotnet20-builder-img: Dockerfile
\ No newline at end of file
diff --git a/dotnet60/builder/Model/ExcludeDll.cs b/dotnet60/builder/Model/ExcludeDll.cs
new file mode 100644
index 00000000..75765e85
--- /dev/null
+++ b/dotnet60/builder/Model/ExcludeDll.cs
@@ -0,0 +1,10 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Builder.Model
+{
+ public readonly record struct ExcludeDll(
+ string dllName, string packageName
+ );
+}
diff --git a/dotnet60/builder/Model/FissionContext.cs b/dotnet60/builder/Model/FissionContext.cs
new file mode 100644
index 00000000..256fb0aa
--- /dev/null
+++ b/dotnet60/builder/Model/FissionContext.cs
@@ -0,0 +1,131 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Security.Cryptography.X509Certificates;
+using System.Text;
+using Nancy;
+using Newtonsoft.Json;
+
+
+namespace Fission.DotNet.Api
+{
+ public class FissionContext
+ {
+ public FissionContext(Dictionary args, Logger logger, FissionHttpRequest request)
+ {
+ if (args == null) throw new ArgumentNullException(nameof(args));
+ if (logger == null) throw new ArgumentNullException(nameof(logger));
+ if (request == null) throw new ArgumentNullException(nameof(request));
+ Arguments = args;
+ Logger = logger;
+ Request = request;
+ }
+
+ public Dictionary Arguments { get; private set; }
+
+ public FissionHttpRequest Request { get; private set; }
+
+ public Logger Logger { get; private set; }
+
+ public static FissionContext Build(Request request, Logger logger)
+ {
+ return new FissionContext(((DynamicDictionary)request.Query).ToDictionary(),
+ logger,
+ new FissionHttpRequest(request));
+ }
+
+ //this are currently dummy , not being implemented, just to pass compilation
+ //actual execution is written in environment to use the app settings as there we need it
+ public T GetSettings(string relativePath)
+ {
+ throw new NotImplementedException();
+ }
+
+ //this are currently dummy , not being implemented, just to pass compilation
+ //actual execution is written in environment to use the app settings as there we need it
+ private string GetSettingsJson(string relativePath)
+ {
+ throw new NotImplementedException();
+ }
+
+ }
+
+ public class Logger
+ {
+ public void Write(Severity severity, string format, params object[] args)
+ {
+ Console.WriteLine($"{DateTime.Now.ToString("MM/dd/yy H:mm:ss zzz")} {severity}: " + format, args);
+ }
+
+ public void WriteInfo(string format, params object[] args)
+ {
+ Write(Severity.Info, format, args);
+ }
+
+ public void WriteWarning(string format, params object[] args)
+ {
+ Write(Severity.Warning, format, args);
+ }
+
+ public void WriteError(string format, params object[] args)
+ {
+ Write(Severity.Error, format, args);
+ }
+
+ public void WriteCritical(string format, params object[] args)
+ {
+ Write(Severity.Critical, format, args);
+ }
+
+ public void WriteVerbose(string format, params object[] args)
+ {
+ Write(Severity.Verbose, format, args);
+ }
+ }
+
+ public enum Severity
+ {
+ Info,
+ Warning,
+ Error,
+ Critical,
+ Verbose
+ }
+
+ public class FissionHttpRequest
+ {
+ private readonly Request _request;
+ internal FissionHttpRequest(Request request)
+ {
+ if (request == null) throw new ArgumentNullException(nameof(request));
+ _request = request;
+ }
+
+ public Stream Body { get { return _request.Body; } }
+
+ public string BodyAsString()
+ {
+ int length = (int)_request.Body.Length;
+ byte[] data = new byte[length];
+ _request.Body.Read(data, 0, length);
+ return Encoding.UTF8.GetString(data);
+ }
+
+ public Dictionary> Headers
+ {
+ get
+ {
+ var headers = new Dictionary>();
+ foreach (var kv in _request.Headers)
+ {
+ headers.Add(kv.Key, kv.Value);
+ }
+ return headers;
+ }
+ }
+
+ public X509Certificate Certificate { get { return _request.ClientCertificate; } }
+ public string Url { get { return _request.Url.ToString(); } }
+ public string Method { get { return _request.Method; } }
+ }
+}
\ No newline at end of file
diff --git a/dotnet60/builder/Model/IncludeNuget.cs b/dotnet60/builder/Model/IncludeNuget.cs
new file mode 100644
index 00000000..8e890b0b
--- /dev/null
+++ b/dotnet60/builder/Model/IncludeNuget.cs
@@ -0,0 +1,10 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Builder.Model
+{
+ public readonly record struct IncludeNuget(
+ string packageName, string version
+ );
+}
diff --git a/dotnet60/builder/README.md b/dotnet60/builder/README.md
new file mode 100644
index 00000000..bc4aa715
--- /dev/null
+++ b/dotnet60/builder/README.md
@@ -0,0 +1,85 @@
+# Fission: .NET 6.0 C# Environment Builder
+
+This is a .NET 6.0 C# environment builder for Fission. It supports building multi-file projects with NuGet dependencies.
+
+During build, it also does a pre-compilation to prevent any compilation issues during function environment pod specialization.
+Thus we get the function compilation issues during builder phase in package info's build logs itself.
+
+Once the build is finished, the output package (deploy archive) will be uploaded to storagesvc to store.
+Then, during the specialization, the fetcher inside function pod will fetch the package from storagesvc for function loading and will call on the **/v2/specialize** endpoint of fission environment with required parameters.
+
+There further environment will compile it and execute the function.
+
+## Examples
+
+See `/examples/builder-example` for a complete example.
+
+Example of simplest possible class to be executed:
+
+The source package structure in zip file :
+
+```
+ Source Package zip :
+ --soruce.zip
+ |--func.cs
+ |--nuget.txt
+ |--exclude.txt
+ |--....MiscFiles(optional)
+ |--....MiscFiles(optional)
+```
+
+**func.cs** --> This contains original function body with Executing method name as : Execute
+
+
+**nuget.txt**--> this file contains list of nuget packages required by your function , in this file put one line per nuget with nugetpackage name:version(optional) format, for example :
+
+```
+RestSharp
+CsvHelper
+Newtonsoft.json:10.2.1.0
+```
+
+ **exclude.txt**--> list of dlls that will be excluded from compilation
+
+```
+Newtonsoft.json:Newtonsoft.json.dll
+```
+
+## Usage
+
+```
+fission env list
+fission fn list
+ ```
+ Create Environment with builder, supposing that the builder image name is `fission/dotnet6-builder` and hosted on dockerhub as `fission/dotnet6-builder`
+ ```
+fission environment create --name dotnetwithnuget --image fission/dotnet6 --builder fission/dotnet6-builder
+ ```
+ Verify fission-builder and fission-function namespace for new pods (pods name beginning with env name which we have given like *dotnetwithnuget-xxx-xxx*)
+ ```
+kubectl get pods -n fission-builder
+kubectl get pods -n fission-function
+ ```
+Create a package from source zip using this environment name
+ ```
+fission package create --src funccsv.zip --env dotnetwithnuget
+ ```
+Check package status
+ ```
+fission package info --name funccsv-zip-xyz
+```
+
+#Status of package should be *failed / running / succeeded* .
+Wait if the status is running, until it fails or succeeded. For detailed build logs, you can shell into builder pod in fission-builder namespace and verify log location mentioned in above command's result output.
+
+Now If the result is succeeded , then go ahead and create function using this package.
+
+*--entrypoint* flag is optional if your function body file name is func.cs (which it should be as builder need that), else put the filename (without extension)
+ ```
+ fission fn create --name dotnetcsvtest --pkg funccsv-zip-xyz --env dotnetcorewithnuget --entrypoint "func"
+ ```
+Test the function execution:
+```
+ fission fn test --name dotnetcsvtest
+```
+Above would execute the function and will output the enum value as written in dll.
\ No newline at end of file
diff --git a/dotnet60/builder/Utility/BuilderHelper.cs b/dotnet60/builder/Utility/BuilderHelper.cs
new file mode 100644
index 00000000..3883bf39
--- /dev/null
+++ b/dotnet60/builder/Utility/BuilderHelper.cs
@@ -0,0 +1,154 @@
+using Builder.Model;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+using System.Text.RegularExpressions;
+using System.Linq;
+using System.Text.Json;
+
+using Fission.Common;
+
+namespace Builder.Utility
+{
+ public sealed class BuilderHelper
+ {
+ private static readonly Lazy lazy =
+ new Lazy(() => new BuilderHelper());
+
+ public string _logFileName = string.Empty;
+ public static BuilderHelper Instance { get { return lazy.Value; } }
+
+ private static Logger _logger = new Logger("Initial.log");
+
+ public Logger logger
+ {
+ get
+ {
+ return _logger;
+ }
+ set
+ {
+ _logger = value;
+ }
+ }
+
+ static BuilderHelper()
+ {
+ }
+
+ private BuilderHelper()
+ {
+ }
+
+ public List GetNugetToInclude(string directoryPath)
+ {
+ List includeNugets = new List();
+ string includeNugetsFilePath = Path.Combine(directoryPath, CompilerHelper.Instance.builderSettings.NugetSpecsFile);
+ if (File.Exists(includeNugetsFilePath))
+ {
+ Regex _pkgName = new Regex(CompilerHelper.Instance.builderSettings.NugetPackageRegEx,
+ RegexOptions.Compiled);
+
+ string filetext = File.ReadAllText(includeNugetsFilePath);
+ var _pkgMatchCollection = _pkgName.Matches(filetext);
+
+ foreach (Match match in _pkgMatchCollection)
+ {
+ if(!string.IsNullOrWhiteSpace(match.Value))
+ {
+ string package = match.Groups["package"]?.Value?.Trim();
+ string version = match.Groups["version"]?.Value?.Trim();
+ this.logger.Log($"adding {package} | {version} to includeNugets collection");
+
+ includeNugets.Add(new IncludeNuget()
+ {
+ packageName = package,
+ version = version
+ }
+ );
+ }
+
+ }
+ }
+
+ return includeNugets;
+ }
+
+ public List GetDllsToExclude(string directoryPath)
+ {
+ List excludeDlls = new List();
+ string excludeDllsFilePath = Path.Combine(directoryPath, CompilerHelper.Instance.builderSettings.DllExcludeFile);
+ if (File.Exists(excludeDllsFilePath))
+ {
+ // xyzPackage:abc.dll
+ Regex _exclude = new Regex(CompilerHelper.Instance.builderSettings.ExcludeDllRegEx,
+ RegexOptions.Compiled);
+
+ string filetext = File.ReadAllText(excludeDllsFilePath);
+ var _excludeMatchCollection = _exclude.Matches(filetext);
+
+ foreach (Match match in _excludeMatchCollection)
+ {
+ if (!string.IsNullOrWhiteSpace(match.Value))
+ {
+ string _package = match.Groups["package"]?.Value?.Trim();
+ string _dllName = match.Groups["dll"]?.Value?.Trim();
+ this.logger.Log($"adding {_package} | {_dllName} to excludeDlls collection");
+
+ excludeDlls.Add(
+ new ExcludeDll()
+ {
+ packageName = _package,
+ dllName = _dllName
+ }
+ );
+ }
+ }
+ }
+
+ return excludeDlls;
+ }
+
+ public string DeepException(Exception ex)
+ {
+ string response = string.Empty;
+
+ response = " Exception : LEVEL 1: " + Environment.NewLine + ex.Message;
+ if (ex.InnerException != null)
+ {
+ response = response + Environment.NewLine + "LEVEL 2:" + Environment.NewLine + ex.InnerException.Message;
+ if (ex.InnerException.InnerException != null)
+ {
+ response = response + Environment.NewLine + "LEVEL 3:" + Environment.NewLine + ex.InnerException.InnerException.Message;
+
+ if (ex.InnerException.InnerException.InnerException != null)
+ {
+ response = response + Environment.NewLine + "LEVEL 4:" + Environment.NewLine + ex.InnerException.InnerException.InnerException.Message;
+ if (ex.InnerException.InnerException.InnerException.InnerException != null)
+ {
+ response = response + Environment.NewLine + "LEVEL 5:" + Environment.NewLine + ex.InnerException.InnerException.InnerException.InnerException.Message;
+ }
+ }
+ }
+ }
+
+ if(ex.StackTrace != null)
+ {
+ response = response + "|| STACK :"+ ex.StackTrace;
+ }
+
+ return response;
+ }
+
+ public void WriteToFile(string filenameWithPath , string content)
+ {
+ using (StreamWriter sw = new StreamWriter(filenameWithPath, false))
+ {
+ sw.AutoFlush = true;
+ sw.Write(content);
+ }
+
+ }
+ }
+}
diff --git a/dotnet60/builder/Utility/Logger.cs b/dotnet60/builder/Utility/Logger.cs
new file mode 100644
index 00000000..32c24cbf
--- /dev/null
+++ b/dotnet60/builder/Utility/Logger.cs
@@ -0,0 +1,109 @@
+using log4net;
+using NuGet.Common;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using System.Threading.Tasks;
+using System.Xml;
+
+namespace Builder.Utility
+{
+ public class Logger : NuGet.Common.ILogger
+ {
+ private ILog _ILog { get; set; }
+ public Logger(string logpath)
+ {
+ XmlDocument ConfigLoader = new XmlDocument();
+ ConfigLoader.Load(File.OpenRead("log4net.config"));
+ var repo = LogManager.CreateRepository(Assembly.GetEntryAssembly(),
+ typeof(log4net.Repository.Hierarchy.Hierarchy));
+ log4net.Config.XmlConfigurator.Configure(repo, ConfigLoader["log4net"]);
+
+ var appender = ((log4net.Appender.FileAppender)repo.GetAppenders().Where(x => x.Name == "RollingLogFileAppender").FirstOrDefault());
+ appender.File = logpath;
+
+ appender.ActivateOptions();
+ _ILog = LogManager.GetLogger(typeof(Logger));
+ }
+
+ public void Log(string message,bool logToConsoleAsWell=false)
+ {
+ if(logToConsoleAsWell)
+ Console.WriteLine(message);
+
+ _ILog.Info(message);
+ }
+
+ public void Log(LogLevel level, string data)
+ {
+ //Console.WriteLine(data);
+ _ILog.Info(data);
+ }
+
+ public void Log(ILogMessage message)
+ {
+ //Console.WriteLine(message);
+ _ILog.Info(message.Message);
+ }
+
+ public Task LogAsync(LogLevel level, string data)
+ {
+ //Console.WriteLine(data);
+ _ILog.Info(data);
+ return null;
+ }
+
+ public Task LogAsync(ILogMessage message)
+ {
+ //Console.WriteLine(message);
+ _ILog.Info(message.Message);
+ return null;
+ }
+
+ public void LogDebug(string data)
+ {
+ //Console.WriteLine(data);
+ _ILog.Debug(data);
+
+ }
+
+ public void LogError(string data)
+ {
+ //Console.WriteLine(data);
+ _ILog.Error(data);
+ }
+
+ public void LogInformation(string data)
+ {
+ //Console.WriteLine(data);
+ _ILog.Info(data);
+ }
+
+ public void LogInformationSummary(string data)
+ {
+ //Console.WriteLine(data);
+ _ILog.Info(data);
+ }
+
+ public void LogMinimal(string data)
+ {
+ //Console.WriteLine(data);
+ _ILog.Info(data);
+ }
+
+ public void LogVerbose(string data)
+ {
+ //Console.WriteLine(data);
+ _ILog.Debug(data);
+ }
+
+ public void LogWarning(string data)
+ {
+ //Console.WriteLine(data);
+ _ILog.Warn(data);
+ }
+ }
+}
diff --git a/dotnet60/builder/build.sh b/dotnet60/builder/build.sh
new file mode 100644
index 00000000..a9f1dda3
--- /dev/null
+++ b/dotnet60/builder/build.sh
@@ -0,0 +1,17 @@
+#!/bin/bash
+set -euxo pipefail
+cd ${SRC_PKG}
+#now start execution of custom logic dll in such a way that it should copy everything in ${SRC_PKG}
+#first lets try putting sample file which will prove that this worked
+echo src : ${SRC_PKG} ,dest: ${DEPLOY_PKG} > builderpaths.txt
+
+#now run actual dll for custom builder logic
+# please note as this need to be executed from app folder so that all dependent files are avilable
+# else you will end up getting File not found error
+cd /app
+
+#now execute dll
+dotnet Builder.dll
+
+#copy entire content to deployment package
+cp -r ${SRC_PKG} ${DEPLOY_PKG}
\ No newline at end of file
diff --git a/dotnet60/builder/builderSettings.json b/dotnet60/builder/builderSettings.json
new file mode 100644
index 00000000..a05a46ea
--- /dev/null
+++ b/dotnet60/builder/builderSettings.json
@@ -0,0 +1,11 @@
+{
+ "NugetSpecsFile": "nuget.txt",
+ "DllExcludeFile": "exclude.txt",
+ "BuildLogDirectory": "logs",
+ "DllDirectory": "Dlls",
+ "NugetPackageRegEx": "\\s*(?[^:\\n]*)(?:\\:)?(?.*)?",
+ "ExcludeDllRegEx": "\\:?\\s*(?[^:\\n]*)(?:\\:)?(?.*)?",
+ "RunningOnWindows": false,
+ "functionBodyFileName": "func.cs",
+ "functionSpecFileName": "func.meta.json"
+}
\ No newline at end of file
diff --git a/dotnet60/builder/log4net.config b/dotnet60/builder/log4net.config
new file mode 100644
index 00000000..7ae56e49
--- /dev/null
+++ b/dotnet60/builder/log4net.config
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/dotnet60/builder/nugetSettings.json b/dotnet60/builder/nugetSettings.json
new file mode 100644
index 00000000..1303b350
--- /dev/null
+++ b/dotnet60/builder/nugetSettings.json
@@ -0,0 +1,37 @@
+{
+ "NugetFolder": "Nugetdownload",
+ "DisableCache": false,
+ "CSVDirectory": "logs",
+ "RunningOnWindows": false,
+ "NugetRepositories": [
+ {
+ "Order": 1,
+ "IsPrivate": false,
+ "Name": "local",
+ "Source": "Nugetdownload", //in case of local , relative path to folder
+ "IsPasswordClearText": false,
+ "Username": "",
+ "Password": ""
+ },
+ {
+ "Order": 2,
+ "IsPrivate": false,
+ "Name": "NugetV3",
+ "Source": "https://api.nuget.org/v3/index.json",
+ "IsPasswordClearText": false,
+ "Username": "",
+ "Password": ""
+ }
+ //,
+ //{
+ // "Order": 3,
+ // "IsPrivate": true,
+ // "Name": "myPrivateRepository", //in case of private repo , if not using, then just remove this section No 3
+ // "Source": "https://URL-FOR-myPrivateRepository/api/nuget/nugetcore/COMPLETE-END-POINT",
+ // "IsPasswordClearText": true,
+ // "Username": "",
+ // "Password": ""
+ //}
+
+ ]
+}
\ No newline at end of file
diff --git a/dotnet60/examples/builder-example/MyClass.cs b/dotnet60/examples/builder-example/MyClass.cs
new file mode 100644
index 00000000..69b039da
--- /dev/null
+++ b/dotnet60/examples/builder-example/MyClass.cs
@@ -0,0 +1,38 @@
+using System;
+using System.Collections.Generic;
+
+public readonly record struct MyStruct(string myField);
+
+public sealed class MyClass
+{
+ private static readonly Lazy lazy =
+ new Lazy(() => new MyClass());
+
+ public static MyClass Instance { get { return lazy.Value; } }
+
+ private double _myValue = 0;
+
+ public double myValue
+ {
+ get
+ {
+ if (_myValue == 0)
+ {
+ _myValue = MathNet.Numerics.SpecialFunctions.Erf(0.5);
+ }
+ return _myValue;
+ }
+ set
+ {
+ myValue = value;
+ }
+ }
+
+ static MyClass()
+ {
+ }
+
+ private MyClass()
+ {
+ }
+}
diff --git a/dotnet60/examples/builder-example/exclude.txt b/dotnet60/examples/builder-example/exclude.txt
new file mode 100644
index 00000000..e69de29b
diff --git a/dotnet60/examples/builder-example/func.cs b/dotnet60/examples/builder-example/func.cs
new file mode 100644
index 00000000..743a67e5
--- /dev/null
+++ b/dotnet60/examples/builder-example/func.cs
@@ -0,0 +1,22 @@
+using System;
+using Fission.Functions;
+
+public class HelloWorld : IFissionFunction
+{
+ public object Execute(FissionContext context)
+ {
+ string response = "initial value";
+ try
+ {
+ context.Logger.WriteInfo("Starting...");
+ response = MyClass.Instance.myValue.ToString();
+ }
+ catch(Exception ex)
+ {
+ context.Logger.WriteError(ex.Message);
+ response = ex.Message;
+ }
+ context.Logger.WriteInfo("Done");
+ return response;
+ }
+}
\ No newline at end of file
diff --git a/dotnet60/examples/builder-example/nuget.txt b/dotnet60/examples/builder-example/nuget.txt
new file mode 100644
index 00000000..3d2871e4
--- /dev/null
+++ b/dotnet60/examples/builder-example/nuget.txt
@@ -0,0 +1 @@
+MathNet.Numerics
diff --git a/dotnet60/examples/hello-world/HelloWorld.cs b/dotnet60/examples/hello-world/HelloWorld.cs
new file mode 100644
index 00000000..625da081
--- /dev/null
+++ b/dotnet60/examples/hello-world/HelloWorld.cs
@@ -0,0 +1,10 @@
+using System;
+using Fission.Functions;
+
+public class HelloWorld : IFissionFunction
+{
+ public object Execute(FissionContext context)
+ {
+ return "hello, world!";
+ }
+}
diff --git a/dotnet60/fission-dotnet6.sln b/dotnet60/fission-dotnet6.sln
new file mode 100644
index 00000000..46f8b815
--- /dev/null
+++ b/dotnet60/fission-dotnet6.sln
@@ -0,0 +1,39 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30804.86
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "fission-dotnet6", "fission-dotnet6\fission-dotnet6.csproj", "{7FDAA994-D65D-4525-8375-EE77CF150AB8}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Fission.Functions", "Fission.Functions\Fission.Functions.csproj", "{A04A5119-DEF9-467E-9ABC-5030F2EF38CF}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{A91D1E8C-4FB8-4A18-90D4-BC94440CE5DC}"
+ ProjectSection(SolutionItems) = preProject
+ .dockerignore = .dockerignore
+ Dockerfile = Dockerfile
+ LICENSE = LICENSE
+ README.md = README.md
+ EndProjectSection
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {7FDAA994-D65D-4525-8375-EE77CF150AB8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {7FDAA994-D65D-4525-8375-EE77CF150AB8}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {7FDAA994-D65D-4525-8375-EE77CF150AB8}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {7FDAA994-D65D-4525-8375-EE77CF150AB8}.Release|Any CPU.Build.0 = Release|Any CPU
+ {A04A5119-DEF9-467E-9ABC-5030F2EF38CF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {A04A5119-DEF9-467E-9ABC-5030F2EF38CF}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A04A5119-DEF9-467E-9ABC-5030F2EF38CF}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {A04A5119-DEF9-467E-9ABC-5030F2EF38CF}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {EB21B789-DB52-41EC-87D2-B6618931797C}
+ EndGlobalSection
+EndGlobal
diff --git a/dotnet60/fission-dotnet6/BuilderRequest.cs b/dotnet60/fission-dotnet6/BuilderRequest.cs
new file mode 100644
index 00000000..1b575c87
--- /dev/null
+++ b/dotnet60/fission-dotnet6/BuilderRequest.cs
@@ -0,0 +1,23 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Fission.DotNet
+{
+ public readonly record struct FunctionMetadata(
+ string name,
+ string @namespace,
+ string selfLink,
+ string uid,
+ string resourceVersion,
+ int generation,
+ DateTime creationTimestamp
+ );
+
+ public readonly record struct BuilderRequest(
+ string filepath,
+ string functionName,
+ string url,
+ FunctionMetadata FunctionMetadata
+ );
+}
diff --git a/dotnet60/fission-dotnet6/Controllers/FunctionController.cs b/dotnet60/fission-dotnet6/Controllers/FunctionController.cs
new file mode 100644
index 00000000..d5a946a1
--- /dev/null
+++ b/dotnet60/fission-dotnet6/Controllers/FunctionController.cs
@@ -0,0 +1,187 @@
+#region header
+
+// fission-dotnet6 - FunctionController.cs
+//
+// Created by: Alistair J R Young(avatar) at 2020/12/28 11:19 PM.
+
+#endregion
+
+#region using
+
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Net;
+
+using Fission.DotNet.Properties;
+using Fission.Functions;
+
+using JetBrains.Annotations;
+
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Http.Extensions;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Primitives;
+
+#endregion
+
+namespace Fission.DotNet.Controllers
+{
+ ///
+ /// Controller handling calls to the Fission function in this environment container.
+ ///
+ [ApiController]
+ [Route(template: "/")]
+ public class FunctionController : ControllerBase
+ {
+ private readonly ILogger funcLogger;
+ private readonly ILogger logger;
+ private readonly IFunctionStore store;
+
+ ///
+ /// Creates an instance of this .
+ ///
+ /// A logger for the .
+ /// A logger for the function invoked by the .
+ /// The function storage service(see ).
+ ///
+ /// The second logger exists to permit ready differentiation of function-internal errors and other messages from those
+ /// originating with the host environment.
+ ///
+ public FunctionController(ILogger logger, ILogger funcLogger, IFunctionStore store)
+ {
+ this.logger = logger;
+ this.funcLogger = funcLogger;
+ this.store = store;
+ }
+
+ ///
+ /// Handle HTTP GET requests by forwarding to the Fission function.
+ ///
+ /// The function return value.
+ [HttpGet]
+ [NotNull]
+ public object Get() => this.Run();
+
+ ///
+ /// Handle HTTP POST requests by forwarding to the Fission function.
+ ///
+ /// The function return value.
+ [HttpPost]
+ [NotNull]
+ public object Post() => this.Run();
+
+ ///
+ /// Handle HTTP PUT requests by forwarding to the Fission function.
+ ///
+ /// The function return value.
+ [HttpPut]
+ [NotNull]
+ public object Put() => this.Run();
+
+ ///
+ /// Handle HTTP HEAD requests by forwarding to the Fission function.
+ ///
+ /// The function return value.
+ [HttpHead]
+ [NotNull]
+ public object Head() => this.Run();
+
+ ///
+ /// Handle HTTP OPTIONS requests by forwarding to the Fission function.
+ ///
+ /// The function return value.
+ [HttpOptions]
+ [NotNull]
+ public object Options() => this.Run();
+
+ ///
+ /// Handle HTTP DELETE requests by forwarding to the Fission function.
+ ///
+ /// The function return value.
+ [HttpDelete]
+ [NotNull]
+ public object Delete() => this.Run();
+
+ ///
+ /// Invokes the Fission function on behalf of the caller.
+ ///
+ ///
+ /// 200 OK with the Fission function return value; or 400 Bad Request with the exception message if an exception
+ /// occurred in the Fission function; or 500 Internal Server Error if the environment container has not yet been
+ /// specialized.
+ ///
+ [NotNull]
+ private object Run()
+ {
+ this.logger.LogInformation(message: "Invoking function");
+
+ if(this.store.Func == null)
+ {
+ this.logger.LogError(message: Resources.FunctionController_Run_GenericContainer);
+
+ return this.StatusCode(statusCode:(int) HttpStatusCode.InternalServerError,
+ value: Resources.FunctionController_Run_GenericContainer);
+ }
+
+ try
+ {
+ FissionContext context = this.BuildContext();
+ this.logger.LogInformation(message: "Context built");
+ return this.Ok(value: this.store.Func.Invoke(context: context));
+ }
+ catch (Exception e)
+ {
+ this.logger.LogError(message: e.Message);
+ return this.StatusCode(statusCode:(int) HttpStatusCode.BadRequest, value: e.Message);
+ }
+ }
+
+ ///
+ /// Build the context for the Fission function, assembling data from the call request and the function logger.
+ ///
+ /// The path to the function package.
+ /// A to be passed to the Fission function.
+ private FissionContext BuildContext(string packagePath = "")
+ {
+ var fl = new FissionLogger
+ {
+ WriteInfo =(format, objects) => this.funcLogger.LogInformation(message: format, args: objects),
+ WriteWarning =(format, objects) => this.funcLogger.LogWarning(message: format, args: objects),
+ WriteError =(format, objects) => this.funcLogger.LogError(message: format, args: objects),
+ WriteCritical =(format, objects) => this.funcLogger.LogCritical(message: format, args: objects),
+ };
+
+ IQueryCollection arguments = this.Request.Query;
+
+ var args = new Dictionary();
+
+ foreach(var k in arguments.Keys) args[key: k] = arguments[key: k];
+
+ var headers = new Dictionary>();
+
+ foreach(KeyValuePair kv in this.Request.Headers)
+ headers.Add(key: kv.Key, value: kv.Value);
+
+ var fr = new FissionRequest
+ {
+ Body = this.Request.Body,
+ ClientCertificate = this.Request.HttpContext.Connection.ClientCertificate,
+ Headers = new ReadOnlyDictionary>(dictionary: headers),
+ Method = this.Request.Method,
+ Url = this.Request.GetEncodedUrl(),
+ };
+
+ var fc = new FissionContext
+ {
+ Logger = fl,
+ Arguments = new ReadOnlyDictionary(dictionary: args),
+ Request = fr,
+ PackagePath = packagePath,
+ };
+
+ return fc;
+ }
+ }
+}
diff --git a/dotnet60/fission-dotnet6/Controllers/HealthController.cs b/dotnet60/fission-dotnet6/Controllers/HealthController.cs
new file mode 100644
index 00000000..282db7e7
--- /dev/null
+++ b/dotnet60/fission-dotnet6/Controllers/HealthController.cs
@@ -0,0 +1,34 @@
+#region header
+
+// fission-dotnet6 - HealthController.cs
+//
+// Created by: Alistair J R Young (avatar) at 2020/12/29 12:10 AM.
+
+#endregion
+
+#region using
+
+using JetBrains.Annotations;
+
+using Microsoft.AspNetCore.Mvc;
+
+#endregion
+
+namespace Fission.DotNet.Controllers
+{
+ ///
+ /// Controller to handle the Docker/Kubernetes container health-check.
+ ///
+ [Route (template: "/healthz")]
+ [ApiController]
+ public class HealthController : ControllerBase
+ {
+ ///
+ /// When this endpoint receives a GET request, simply return 200 OK to demonstrate that the container is alive.
+ ///
+ /// 200 OK
+ [HttpGet]
+ [NotNull]
+ public object Get () => this.Ok ();
+ }
+}
diff --git a/dotnet60/fission-dotnet6/Controllers/SpecializeController.cs b/dotnet60/fission-dotnet6/Controllers/SpecializeController.cs
new file mode 100644
index 00000000..7ec08c39
--- /dev/null
+++ b/dotnet60/fission-dotnet6/Controllers/SpecializeController.cs
@@ -0,0 +1,100 @@
+#region header
+
+// fission-dotnet6 - SpecializeController.cs
+//
+// Created by: Alistair J R Young(avatar) at 2020/12/29 12:10 AM.
+// Modified by: Vsevolod Kvachev (Rasie1) at 2022.
+
+#endregion
+
+#region using
+
+using System;
+using System.Collections.Generic;
+using System.Net;
+
+using Fission.DotNet.Properties;
+
+using JetBrains.Annotations;
+
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.Extensions.Logging;
+
+#endregion
+
+namespace Fission.DotNet.Controllers
+{
+ ///
+ /// Controller to handle specializing the container to handle a particular Fission function.
+ ///
+ ///
+ /// Essentially, this handles fetching, compiling, and caching the function for later use by the
+ /// .
+ ///
+ [Route(template: "/specialize")]
+ [ApiController]
+ public class SpecializeController : ControllerBase
+ {
+ private readonly ILogger logger;
+ private readonly IFunctionStore store;
+
+ ///
+ /// Creates an instance of the .
+ ///
+ /// A logger instance for the .
+ /// The function store service. See .
+ public SpecializeController(ILogger logger, IFunctionStore store)
+ {
+ this.logger = logger;
+ this.store = store;
+ }
+
+ ///
+ /// The path to the function code to compile. In Debug builds, this invokes a built-in test function to simplify
+ /// debugging without a container. In Release builds, this uses the mount path of the function package.
+ ///
+ [NotNull]
+ private static string CodePath
+#if DEBUG
+ => "tmp/TestFunc.cs";
+#else
+ => "/userfunc/user";
+#endif
+
+ ///
+ /// Handle version 1 requests to specialize the container; i.e., to compile and cache a single-file function.
+ ///
+ /// 200 OK on success; 500 Internal Server Error on failure.
+ [HttpPost]
+ [NotNull]
+ public object Post()
+ {
+ this.logger.LogInformation(message: "/specialize called.");
+
+ if (System.IO.File.Exists(path: SpecializeController.CodePath))
+ {
+ string source = System.IO.File.ReadAllText(path: SpecializeController.CodePath);
+
+ var compiler = new FissionCompiler();
+ FunctionRef? binary = compiler.Compile(source: source, errors: out List errors);
+
+ if (binary == null)
+ {
+ string? error = string.Join(separator: Environment.NewLine, values: errors);
+ this.logger.LogError(message: error);
+ return this.StatusCode(statusCode:(int) HttpStatusCode.InternalServerError, value: error);
+ }
+
+ this.store.SetFunctionRef(func: binary);
+ }
+ else
+ {
+ var error = $"Unable to locate function source code at '{SpecializeController.CodePath}'.";
+ this.logger.LogError(message: error);
+ return this.StatusCode(statusCode:(int) HttpStatusCode.InternalServerError, value: error);
+ }
+
+ return this.Ok();
+ }
+ }
+}
diff --git a/dotnet60/fission-dotnet6/Controllers/V2SpecializeController.cs b/dotnet60/fission-dotnet6/Controllers/V2SpecializeController.cs
new file mode 100644
index 00000000..48775e06
--- /dev/null
+++ b/dotnet60/fission-dotnet6/Controllers/V2SpecializeController.cs
@@ -0,0 +1,120 @@
+#region header
+
+// fission-dotnet6 - V2SpecializeController.cs
+
+#endregion
+
+#region using
+
+using System;
+using System.Collections.Generic;
+using System.Net;
+using System.IO;
+
+using Fission.DotNet.Properties;
+using Fission.Common;
+
+using JetBrains.Annotations;
+
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.Extensions.Logging;
+
+#endregion
+
+namespace Fission.DotNet.Controllers
+{
+ ///
+ /// Controller to handle specializing the container to handle a particular Fission function.
+ ///
+ ///
+ /// Essentially, this handles fetching, compiling, and caching the function for later use by the
+ /// .
+ ///
+ [Route (template: "/v2/specialize")]
+ [ApiController]
+ public class V2SpecializeController : ControllerBase
+ {
+ private readonly ILogger logger;
+ private readonly IFunctionStore store;
+
+ public string GetBodyAsString ()
+ {
+ var length = (int) Request.ContentLength;
+ var data = new byte[length];
+ Request.Body.Read(buffer: data, offset: 0, count: length);
+
+ return System.Text.Encoding.UTF8.GetString(bytes: data);
+ }
+ ///
+ /// Creates an instance of the .
+ ///
+ /// A logger instance for the .
+ /// The function store service. See .
+ public V2SpecializeController (ILogger logger, IFunctionStore store)
+ {
+ this.logger = logger;
+ this.store = store;
+ }
+
+ ///
+ /// Handle version 2 requests to specialize the container; i.e., to compile and cache a multi-file function.
+ ///
+ /// 200 OK on success; 500 Internal Server Error on failure.
+ [HttpPost]
+ [NotNull]
+ public object Post ()
+ {
+ this.logger.LogInformation (message: "/v2/specialize called.");
+ var errors = new List();
+ var oinfo = new List();
+ var body = GetBodyAsString();
+ Console.WriteLine($"Request received by endpoint from builder: {body}");
+ var builderRequest = System.Text.Json.JsonSerializer.Deserialize(body);
+
+ string functionPath = string.Empty;
+
+ store.SetPackagePath(builderRequest.filepath);
+
+ // following will enable us to skip --entrypoint flag during function creation
+ if (!string.IsNullOrWhiteSpace(builderRequest.functionName))
+ {
+ functionPath = System.IO.Path.Combine(builderRequest.filepath, $"{builderRequest.functionName}.cs");
+ }
+ else
+ {
+ functionPath = System.IO.Path.Combine(builderRequest.filepath, CompilerHelper.Instance.builderSettings.functionBodyFileName);
+ }
+
+ Console.WriteLine($"Going to read function body from path: {functionPath}");
+
+ if (!System.IO.File.Exists(functionPath))
+ {
+ var error = $"Unable to locate function source code at '{functionPath}'.";
+ this.logger.LogError(message: error);
+ return this.StatusCode(statusCode:(int) HttpStatusCode.InternalServerError, value: error);
+ }
+ var code = System.IO.File.ReadAllText(functionPath);
+ FunctionRef? binary = null;
+ try
+ {
+ FissionCompiler fissionCompiler = new FissionCompiler();
+ binary = fissionCompiler.CompileV2(builderRequest.filepath, out errors, out oinfo);
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"Error getting function: {ex.Message}, Trace: {ex.StackTrace}");
+ }
+ if (binary == null)
+ {
+ string? error = string.Join(separator: Environment.NewLine, values: errors);
+ this.logger.LogError(message: error);
+ return this.StatusCode(statusCode:(int) HttpStatusCode.InternalServerError, value: error);
+ }
+ else
+ {
+ store.SetFunctionRef(binary);
+ }
+ return this.Ok();
+ }
+ }
+}
diff --git a/dotnet60/fission-dotnet6/FissionCompiler.cs b/dotnet60/fission-dotnet6/FissionCompiler.cs
new file mode 100644
index 00000000..e5ee3671
--- /dev/null
+++ b/dotnet60/fission-dotnet6/FissionCompiler.cs
@@ -0,0 +1,233 @@
+
+// fission-dotnet6 - FissionCompiler.cs
+//
+// Created by: Alistair J R Young(avatar) at 2020/12/29 9:08 AM.
+// Modified by: Vsevolod Kvachev (Rasie1) at 2022.
+
+
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using System.Runtime.Loader;
+using System.Runtime.Serialization.Json;
+
+using Fission.DotNet.Properties;
+using Fission.Functions;
+using Fission.Common;
+
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.Emit;
+
+
+namespace Fission.DotNet
+{
+ ///
+ /// The compiler which builds Fission functions from source text, when a builder container is not used.
+ ///
+ internal class FissionCompiler
+ {
+ ///
+ /// Compile C# source text(implementing ) to an assembly stored in memory.
+ ///
+ /// The source code to compile.
+ /// On exit, a list of compilation errors.
+ /// A referencing the compiled Fission function.
+
+ // ReSharper disable once MemberCanBeMadeStatic.Global
+ [SuppressMessage(category: "Performance",
+ checkId: "CA1822:Mark members as static",
+ Justification = "Instance members are expected in later iterations. -- AJRY 2020/12/30")]
+ internal FunctionRef? Compile(string source, out List errors)
+ {
+ errors = new List();
+
+ var options = CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.Latest);
+ SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(source, options);
+
+ var coreDir = Directory.GetParent(path: typeof(Enumerable).GetTypeInfo().Assembly.Location);
+
+ var references = new List
+ {
+ MetadataReference.CreateFromFile(path: $"{coreDir!.FullName}{Path.DirectorySeparatorChar}mscorlib.dll"),
+ MetadataReference.CreateFromFile(path: typeof(object).GetTypeInfo().Assembly.Location),
+ MetadataReference.CreateFromFile(path: typeof(IFissionFunction).GetTypeInfo().Assembly.Location),
+ MetadataReference.CreateFromFile(path: Assembly.GetEntryAssembly()!.Location),
+ MetadataReference.CreateFromFile(path: typeof(DataContractJsonSerializer).GetTypeInfo().Assembly.Location),
+ };
+
+ foreach (var referencedAssembly in Assembly.GetEntryAssembly()!.GetReferencedAssemblies())
+ {
+ var loaded = Assembly.Load(assemblyRef: referencedAssembly);
+ references.Add(item: MetadataReference.CreateFromFile(path: loaded.Location));
+ }
+
+ string assemblyName = Path.GetRandomFileName();
+ CSharpCompilation compilation = CSharpCompilation.Create(assemblyName: assemblyName,
+ syntaxTrees: new[] {syntaxTree,},
+ references: references,
+ options: new CSharpCompilationOptions(
+ outputKind: OutputKind.DynamicallyLinkedLibrary,
+ optimizationLevel: OptimizationLevel.Release));
+
+ using var ms = new MemoryStream();
+
+ EmitResult result = compilation.Emit(peStream: ms);
+
+ if (!result.Success)
+ {
+ Console.WriteLine($"Compile failed, see pod logs for more details");
+ IEnumerable failures = result.Diagnostics
+ .Where(predicate: diagnostic =>
+ diagnostic.IsWarningAsError ||
+ diagnostic.Severity ==
+ DiagnosticSeverity.Error)
+ .ToList();
+
+ foreach (Diagnostic diagnostic in failures) {
+ errors.Add(item: $"{diagnostic.Id}: {diagnostic.GetMessage()}");
+ Console.WriteLine($"COMPILE ERROR :{diagnostic.Id}: {diagnostic.GetMessage()}", "ERROR");
+ }
+ return null;
+ }
+
+ ms.Seek(offset: 0, loc: SeekOrigin.Begin);
+
+ Assembly assembly = AssemblyLoadContext.Default.LoadFromStream(assembly: ms);
+
+ Type? type = assembly.GetTypes()
+ .FirstOrDefault(predicate: t => typeof(IFissionFunction).IsAssignableFrom(c: t));
+
+ if (type == null)
+ {
+ errors.Add(item: Resources.FissionCompiler_Compile_NoEntrypoint);
+ return null;
+ }
+
+ return new FunctionRef(assembly: assembly, type: type);
+ }
+
+ public FunctionRef? CompileV2(string packagePath, out List errors, out List outputInfo)
+ {
+ errors = new List();
+ outputInfo = new List();
+ var options = CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.Latest);
+
+ var syntaxTrees = new List();
+ foreach (var codeInDirectory in CompilerHelper.GetCSharpSources(packagePath))
+ {
+ syntaxTrees.Add(CSharpSyntaxTree.ParseText(File.ReadAllText(codeInDirectory), options));
+ }
+
+ string assemblyName = Path.GetRandomFileName();
+
+ var coreDir = Directory.GetParent(typeof(Enumerable).GetTypeInfo().Assembly.Location);
+
+ List references = new List
+ {
+ MetadataReference.CreateFromFile(coreDir.FullName + Path.DirectorySeparatorChar + "mscorlib.dll"),
+ MetadataReference.CreateFromFile(coreDir.FullName + Path.DirectorySeparatorChar + "netstandard.dll"),
+ MetadataReference.CreateFromFile(typeof(object).GetTypeInfo().Assembly.Location),
+ MetadataReference.CreateFromFile(Assembly.GetEntryAssembly().Location),
+ MetadataReference.CreateFromFile(typeof(System.Runtime.Serialization.Json.DataContractJsonSerializer).GetTypeInfo().Assembly.Location)
+ };
+
+ foreach (var referencedAssembly in Assembly.GetEntryAssembly().GetReferencedAssemblies())
+ {
+ var loaded = Assembly.Load(referencedAssembly);
+ references.Add(MetadataReference.CreateFromFile(loaded.Location));
+ }
+
+ functionSpec = CompilerHelper.Instance.GetFunctionSpecs(packagePath);
+
+ foreach (var library in functionSpec.libraries)
+ {
+ string dllCompletePath = CompilerHelper.GetRelevantPathAsPerOS(Path.Combine(packagePath, library.path));
+ references.Add(MetadataReference.CreateFromFile(dllCompletePath));
+ }
+
+ AppDomain currentDomain = AppDomain.CurrentDomain;
+ this.packagePath = packagePath;
+ currentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
+
+ CSharpCompilation compilation = CSharpCompilation.Create(
+ assemblyName,
+ syntaxTrees: syntaxTrees,
+ references: references,
+ options: new CSharpCompilationOptions(
+ OutputKind.DynamicallyLinkedLibrary,
+ optimizationLevel: OptimizationLevel.Release));
+
+ var ms = new MemoryStream();
+ EmitResult result = compilation.Emit(ms);
+
+ if (!result.Success)
+ {
+ Console.WriteLine($"Compile failed, see pod logs for more details");
+ IEnumerable failures = result.Diagnostics.Where(diagnostic =>
+ diagnostic.IsWarningAsError ||
+ diagnostic.Severity == DiagnosticSeverity.Error).ToList();
+
+ foreach (Diagnostic diagnostic in failures)
+ {
+ errors.Add($"{diagnostic.Id}: {diagnostic.GetMessage()}");
+ Console.WriteLine($"COMPILE ERROR :{diagnostic.Id}: {diagnostic.GetMessage()}", "ERROR");
+ }
+
+ return null;
+ }
+
+ Console.WriteLine($"COMPILE SUCCESS!");
+
+ ms.Seek(0, SeekOrigin.Begin);
+
+ Assembly assembly = AssemblyLoadContext.Default.LoadFromStream(ms);
+
+ Type? type = assembly.GetTypes()
+ .FirstOrDefault(predicate: t => typeof(IFissionFunction).IsAssignableFrom(c: t));
+ if (type == null)
+ {
+ errors.Add(item: Resources.FissionCompiler_Compile_NoEntrypoint);
+ return null;
+ }
+
+ return new FunctionRef(assembly, type);
+ }
+
+ private string? packagePath;
+ FunctionSpecification functionSpec;
+
+ private Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
+ {
+ // This handler is called only when the common language runtime tries to bind to the assembly and fails.
+
+ Console.WriteLine($"Dynamically trying to load dll {(args.Name.Substring(0, args.Name.IndexOf(",")).ToString() + ".dll").ToLower()} in parent assembly");
+
+ Assembly myAssembly = null, objExecutingAssemblies;
+ string assemblyPathRelative = "", assemblyPathAbsolute = "";
+
+ objExecutingAssemblies = Assembly.GetExecutingAssembly();
+ AssemblyName[] referencedAssemblyNames = objExecutingAssemblies.GetReferencedAssemblies();
+
+ // load all available dlls from deployment folder in dllinfo object
+ if (functionSpec.libraries.Any(x => x.name.ToLower() ==(args.Name.Substring(0, args.Name.IndexOf(",")).ToString() + ".dll").ToLower()))
+ {
+ assemblyPathRelative = functionSpec.libraries.Where(x => x.name.ToLower() ==(args.Name.Substring(0, args.Name.IndexOf(",")).ToString() + ".dll").ToLower()).FirstOrDefault().path;
+ assemblyPathAbsolute = Path.Combine(packagePath, assemblyPathRelative);
+ Console.WriteLine($"loading dll in parent assembly: {CompilerHelper.GetRelevantPathAsPerOS(assemblyPathAbsolute)}");
+ myAssembly = Assembly.LoadFile(CompilerHelper.GetRelevantPathAsPerOS(assemblyPathAbsolute));
+ Console.WriteLine($"Load success for: {CompilerHelper.GetRelevantPathAsPerOS(assemblyPathAbsolute)}");
+ }
+
+ if (myAssembly == null)
+ {
+ Console.WriteLine($"WARNING! Unable to locate dll: {(args.Name.Substring(0, args.Name.IndexOf(",")).ToString() + ".dll").ToLower()} ", "WARNING");
+ }
+ return myAssembly;
+ }
+ }
+}
diff --git a/dotnet60/fission-dotnet6/FunctionRef.cs b/dotnet60/fission-dotnet6/FunctionRef.cs
new file mode 100644
index 00000000..558d79b6
--- /dev/null
+++ b/dotnet60/fission-dotnet6/FunctionRef.cs
@@ -0,0 +1,48 @@
+#region header
+
+// fission-dotnet6 - FunctionRef.cs
+//
+// Created by: Alistair J R Young (avatar) at 2020/12/29 9:45 AM.
+// Modified by: Vsevolod Kvachev (Rasie1) at 2022.
+
+#endregion
+
+#region using
+
+using System;
+using System.Reflection;
+
+using Fission.Functions;
+
+#endregion
+
+namespace Fission.DotNet
+{
+ ///
+ /// A reference to a Fission function, used to invoke it.
+ ///
+ public class FunctionRef
+ {
+ private readonly Assembly assembly;
+ private readonly Type type;
+
+ ///
+ /// Create an instance of a Fission function.
+ ///
+ /// The assembly containing the Fission function.
+ /// The type, implementing , containing the Fission function.
+ public FunctionRef (Assembly assembly, Type type)
+ {
+ this.assembly = assembly;
+ this.type = type;
+ }
+
+ ///
+ /// Invoke the Fission function referenced by this FunctionRef instance.
+ ///
+ /// The function invocation context.
+ /// The Fission function return value.
+ public object Invoke (FissionContext context)
+ => ((IFissionFunction) this.assembly.CreateInstance (typeName: this.type.FullName!)!)!.Execute (context: context);
+ }
+}
diff --git a/dotnet60/fission-dotnet6/FunctionStore.cs b/dotnet60/fission-dotnet6/FunctionStore.cs
new file mode 100644
index 00000000..39e44208
--- /dev/null
+++ b/dotnet60/fission-dotnet6/FunctionStore.cs
@@ -0,0 +1,46 @@
+#region header
+
+// fission-dotnet6 - FunctionStore.cs
+//
+// Created by: Alistair J R Young (avatar) at 2020/12/29 10:41 AM.
+// Modified by: Vsevolod Kvachev (Rasie1) at 2022.
+
+#endregion
+
+#region using
+
+using System;
+
+using Fission.DotNet.Properties;
+
+#endregion
+
+namespace Fission.DotNet
+{
+ ///
+ /// Implementation of the function store service, as defined by .
+ ///
+ internal class FunctionStore : IFunctionStore
+ {
+ private FunctionRef? func;
+ private string? packagePath;
+
+ ///
+ FunctionRef? IFunctionStore.Func => this.func;
+
+ ///
+ void IFunctionStore.SetFunctionRef(FunctionRef func)
+ {
+ this.func = func;
+ }
+
+ ///
+ string? IFunctionStore.PackagePath => this.packagePath;
+
+ ///
+ void IFunctionStore.SetPackagePath(string packagePath)
+ {
+ this.packagePath = packagePath;
+ }
+ }
+}
diff --git a/dotnet60/fission-dotnet6/IFunctionStore.cs b/dotnet60/fission-dotnet6/IFunctionStore.cs
new file mode 100644
index 00000000..ac00b124
--- /dev/null
+++ b/dotnet60/fission-dotnet6/IFunctionStore.cs
@@ -0,0 +1,25 @@
+#region header
+
+// fission-dotnet6 - IFunctionStore.cs
+//
+// Created by: Alistair J R Young (avatar) at 2020/12/29 10:39 AM.
+
+#endregion
+
+namespace Fission.DotNet
+{
+ ///
+ /// Interface for the function store service, which caches the post-specialization function for repeated use by the
+ /// .
+ ///
+ public interface IFunctionStore
+ {
+ public FunctionRef? Func { get; }
+
+ public void SetFunctionRef(FunctionRef func);
+
+ public string? PackagePath { get; }
+
+ public void SetPackagePath(string func);
+ }
+}
diff --git a/dotnet60/fission-dotnet6/Program.cs b/dotnet60/fission-dotnet6/Program.cs
new file mode 100644
index 00000000..752a6548
--- /dev/null
+++ b/dotnet60/fission-dotnet6/Program.cs
@@ -0,0 +1,27 @@
+#region header
+
+// fission-dotnet6 - Program.cs
+//
+// Created by: Alistair J R Young (avatar) at 2020/12/28 11:19 PM.
+
+#endregion
+
+#region using
+
+using Fission.DotNet;
+
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.Extensions.Logging;
+
+#endregion
+
+IWebHost host = new WebHostBuilder()
+ .ConfigureLogging (configureLogging: log => log.AddConsole())
+ .UseKestrel()
+ .UseUrls("http://*:8888")
+ .UseStartup()
+ .Build();
+
+host.Run();
+
+return 0;
diff --git a/dotnet60/fission-dotnet6/Properties/Resources.Designer.cs b/dotnet60/fission-dotnet6/Properties/Resources.Designer.cs
new file mode 100644
index 00000000..5f491f86
--- /dev/null
+++ b/dotnet60/fission-dotnet6/Properties/Resources.Designer.cs
@@ -0,0 +1,90 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:4.0.30319.42000
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace Fission.DotNet.Properties {
+ using System;
+
+
+ ///
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ ///
+ // This class was auto-generated by the StronglyTypedResourceBuilder
+ // class via a tool like ResGen or Visual Studio.
+ // To add or remove a member, edit your .ResX file then rerun ResGen
+ // with the /str option, or rebuild your VS project.
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class Resources {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal Resources() {
+ }
+
+ ///
+ /// Returns the cached ResourceManager instance used by this class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager {
+ get {
+ if (object.ReferenceEquals(resourceMan, null)) {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Fission.DotNet.Properties.Resources", typeof(Resources).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ ///
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture {
+ get {
+ return resourceCulture;
+ }
+ set {
+ resourceCulture = value;
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to FIS0001: No compatible type found during compilation..
+ ///
+ internal static string FissionCompiler_Compile_NoEntrypoint {
+ get {
+ return ResourceManager.GetString("FissionCompiler_Compile_NoEntrypoint", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to generic container: no requests supported.
+ ///
+ internal static string FunctionController_Run_GenericContainer {
+ get {
+ return ResourceManager.GetString("FunctionController_Run_GenericContainer", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Cannot overwrite an existing function..
+ ///
+ internal static string FunctionStore_SetFunctionRef_CannotOverwrite {
+ get {
+ return ResourceManager.GetString("FunctionStore_SetFunctionRef_CannotOverwrite", resourceCulture);
+ }
+ }
+ }
+}
diff --git a/dotnet60/fission-dotnet6/Properties/Resources.resx b/dotnet60/fission-dotnet6/Properties/Resources.resx
new file mode 100644
index 00000000..fe92541f
--- /dev/null
+++ b/dotnet60/fission-dotnet6/Properties/Resources.resx
@@ -0,0 +1,129 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ Cannot overwrite an existing function.
+
+
+ generic container: no requests supported
+
+
+ FIS0001: No compatible type found during compilation.
+
+
\ No newline at end of file
diff --git a/dotnet60/fission-dotnet6/Properties/launchSettings.json b/dotnet60/fission-dotnet6/Properties/launchSettings.json
new file mode 100644
index 00000000..56616c80
--- /dev/null
+++ b/dotnet60/fission-dotnet6/Properties/launchSettings.json
@@ -0,0 +1,15 @@
+{
+ "$schema": "http://json.schemastore.org/launchsettings.json",
+ "profiles": {
+ "fission_dotnet6": {
+ "commandName": "Project",
+ "launchBrowser": true,
+ "launchUrl": "",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ },
+ "dotnetRunMessages": "true",
+ "applicationUrl": "http://localhost:8888"
+ }
+ }
+}
\ No newline at end of file
diff --git a/dotnet60/fission-dotnet6/Startup.cs b/dotnet60/fission-dotnet6/Startup.cs
new file mode 100644
index 00000000..f366fcb0
--- /dev/null
+++ b/dotnet60/fission-dotnet6/Startup.cs
@@ -0,0 +1,51 @@
+#region header
+
+// fission-dotnet6 - Startup.cs
+//
+// Created by: Alistair J R Young (avatar) at 2020/12/28 11:19 PM.
+
+#endregion
+
+#region using
+
+using JetBrains.Annotations;
+
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Hosting;
+
+#endregion
+
+namespace Fission.DotNet
+{
+ ///
+ /// Configure the environment container's web interface.
+ ///
+ public class Startup
+ {
+ [UsedImplicitly]
+ public Startup (IConfiguration configuration) => this.Configuration = configuration;
+
+ public IConfiguration Configuration { get; }
+
+ public void ConfigureServices (IServiceCollection services)
+ {
+ services.AddSingleton();
+ services.AddControllers();
+ services.Configure(options =>
+ {
+ options.AllowSynchronousIO = true;
+ });
+ }
+
+ public void Configure ([NotNull] IApplicationBuilder app, IWebHostEnvironment env)
+ {
+ if (env.IsDevelopment()) app.UseDeveloperExceptionPage();
+ app.UseRouting();
+ app.UseAuthorization();
+ app.UseEndpoints (configure: endpoints => { endpoints.MapControllers(); });
+ }
+ }
+}
diff --git a/dotnet60/fission-dotnet6/appsettings.Development.json b/dotnet60/fission-dotnet6/appsettings.Development.json
new file mode 100644
index 00000000..8983e0fc
--- /dev/null
+++ b/dotnet60/fission-dotnet6/appsettings.Development.json
@@ -0,0 +1,9 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft": "Warning",
+ "Microsoft.Hosting.Lifetime": "Information"
+ }
+ }
+}
diff --git a/dotnet60/fission-dotnet6/appsettings.json b/dotnet60/fission-dotnet6/appsettings.json
new file mode 100644
index 00000000..d9d9a9bf
--- /dev/null
+++ b/dotnet60/fission-dotnet6/appsettings.json
@@ -0,0 +1,10 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft": "Warning",
+ "Microsoft.Hosting.Lifetime": "Information"
+ }
+ },
+ "AllowedHosts": "*"
+}
diff --git a/dotnet60/fission-dotnet6/builderSettings.json b/dotnet60/fission-dotnet6/builderSettings.json
new file mode 100644
index 00000000..a05a46ea
--- /dev/null
+++ b/dotnet60/fission-dotnet6/builderSettings.json
@@ -0,0 +1,11 @@
+{
+ "NugetSpecsFile": "nuget.txt",
+ "DllExcludeFile": "exclude.txt",
+ "BuildLogDirectory": "logs",
+ "DllDirectory": "Dlls",
+ "NugetPackageRegEx": "\\s*(?[^:\\n]*)(?:\\:)?(?.*)?",
+ "ExcludeDllRegEx": "\\:?\\s*(?[^:\\n]*)(?:\\:)?(?.*)?",
+ "RunningOnWindows": false,
+ "functionBodyFileName": "func.cs",
+ "functionSpecFileName": "func.meta.json"
+}
\ No newline at end of file
diff --git a/dotnet60/fission-dotnet6/fission-dotnet6.csproj b/dotnet60/fission-dotnet6/fission-dotnet6.csproj
new file mode 100644
index 00000000..72c45d63
--- /dev/null
+++ b/dotnet60/fission-dotnet6/fission-dotnet6.csproj
@@ -0,0 +1,52 @@
+
+
+
+ net6.0
+ Fission.DotNet
+ enable
+
+
+
+
+
+
+
+
+ PreserveNewest
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ True
+ True
+ Resources.resx
+
+
+
+
+
+ ResXFileCodeGenerator
+ Resources.Designer.cs
+
+
+
+
+
+ Always
+
+
+
+
diff --git a/dotnet60/fission-dotnet6/tmp/TestFunc.cs b/dotnet60/fission-dotnet6/tmp/TestFunc.cs
new file mode 100644
index 00000000..8db74657
--- /dev/null
+++ b/dotnet60/fission-dotnet6/tmp/TestFunc.cs
@@ -0,0 +1,22 @@
+using System;
+using Fission.Functions;
+
+///
+/// Test function for use when debugging.
+///
+public class TestFunc : IFissionFunction
+{
+ ///
+ /// Test function for use when debugging.
+ ///
+ /// Function call context.
+ /// Test parameters added together.
+ public object Execute(FissionContext context)
+ {
+ context.Logger.WriteInfo ("Test message.");
+ //var x = Convert.ToInt32(context.Arguments["x"]);
+ //var y = Convert.ToInt32(context.Arguments["y"]);
+ //return (x + y);
+ return "123";
+ }
+}