diff --git a/environments/dotnet/ExecutorModule.cs b/environments/dotnet/ExecutorModule.cs index ef1d7fd2..311140fb 100644 --- a/environments/dotnet/ExecutorModule.cs +++ b/environments/dotnet/ExecutorModule.cs @@ -64,10 +64,10 @@ namespace Fission.DotNetCore response.StatusCode = HttpStatusCode.InternalServerError; return response; } - var args = ((DynamicDictionary)Request.Query).ToDictionary(); + try { - return _userFunc.Invoke(new FissionContext(args, new Logger())); + return _userFunc.Invoke(FissionContext.Build(Request, new Logger())); } catch (Exception e) { diff --git a/environments/dotnet/FissionCompiler.cs b/environments/dotnet/FissionCompiler.cs index 99f236cd..f4dc4ee6 100644 --- a/environments/dotnet/FissionCompiler.cs +++ b/environments/dotnet/FissionCompiler.cs @@ -26,7 +26,8 @@ namespace Fission.DotNetCore.Compiler { MetadataReference.CreateFromFile(coreDir.FullName + Path.DirectorySeparatorChar + "mscorlib.dll"), MetadataReference.CreateFromFile(typeof(object).GetTypeInfo().Assembly.Location), - MetadataReference.CreateFromFile(Assembly.GetEntryAssembly().Location) + MetadataReference.CreateFromFile(Assembly.GetEntryAssembly().Location), + MetadataReference.CreateFromFile(typeof(System.Runtime.Serialization.Json.DataContractJsonSerializer).GetTypeInfo().Assembly.Location) }; foreach (var referencedAssembly in Assembly.GetEntryAssembly().GetReferencedAssemblies()) diff --git a/environments/dotnet/FissionContext.cs b/environments/dotnet/FissionContext.cs index 977444c7..b4117531 100644 --- a/environments/dotnet/FissionContext.cs +++ b/environments/dotnet/FissionContext.cs @@ -1,46 +1,67 @@ using System; using System.Collections.Generic; +using System.IO; +using System.Security.Cryptography.X509Certificates; +using System.Text; +using Nancy; namespace Fission.DotNetCore.Api { public class FissionContext { - public FissionContext(Dictionary args, Logger logger) + 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)); + } } 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); + Console.WriteLine($"{DateTime.Now.ToString("MM/dd/yy H:mm:ss zzz")} {severity}: " + format, args); } - public void WriteInfo(string format, params object[] args){ + public void WriteInfo(string format, params object[] args) + { Write(Severity.Info, format, args); } - public void WriteWarning(string format, params object[] args){ + public void WriteWarning(string format, params object[] args) + { Write(Severity.Warning, format, args); } - public void WriteError(string format, params object[] args){ + public void WriteError(string format, params object[] args) + { Write(Severity.Error, format, args); } - public void WriteCritical(string format, params object[] args){ + public void WriteCritical(string format, params object[] args) + { Write(Severity.Critical, format, args); } - public void WriteVerbose(string format, params object[] args){ + public void WriteVerbose(string format, params object[] args) + { Write(Severity.Verbose, format, args); } } @@ -53,4 +74,41 @@ namespace Fission.DotNetCore.Api 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/environments/dotnet/README.md b/environments/dotnet/README.md index 9f012558..3e9829d6 100644 --- a/environments/dotnet/README.md +++ b/environments/dotnet/README.md @@ -163,6 +163,114 @@ $ curl "http://$FISSION_ROUTER/add?x=30&y=12" 42 ``` +## Accessing http request information example + +### Setup fission environment +First you need to setup the fission according to your cluster setup as +specified here: https://github.com/fission/fission + + +### Create the class to run + +Secondly you need to create a file /tmp/func.cs containing the following code: + +``` +using System; +using Fission.DotNetCore.Api; + +public class FissionFunction +{ + public string Execute(FissionContext context){ + var buffer = new System.Text.StringBuilder(); + foreach(var header in context.Request.Headers){ + buffer.AppendLine(header.Key); + foreach(var item in header.Value){ + buffer.AppendLine($"\t{item}"); + } + } + buffer.AppendLine($"Url: {context.Request.Url}, method: {context.Request.Method}"); + return buffer.ToString(); + } +} + +``` +### Run the example + +Lastly to run the example: + +``` +$ fission env create --name dotnet --image fission/dotnet-env + +$ fission function create --name httpinfo --env dotnet --code /tmp/func.cs + +$ fission route create --method GET --url /http_info --function httpinfo + +$ curl "http://$FISSION_ROUTER/http_info" +Accept + */*;q=1 +Host + fissionserver:8888 +User-Agent + curl/7.47.0 +Url: http://fissionserver:8888, method: GET + +``` + +## Accessing http request body example + +### Setup fission environment +First you need to setup the fission according to your cluster setup as +specified here: https://github.com/fission/fission + + +### Create the class to run + +Secondly you need to create a file /tmp/func.cs containing the following code: + +``` +using System.IO; +using System.Runtime.Serialization.Json; +using Fission.DotNetCore.Api; + +public class FissionFunction +{ + public string Execute(FissionContext context) + { + var person = Person.Deserialize(context.Request.Body); + return $"Hello, my name is {person.Name} and I am {person.Age} years old."; + } +} + +public class Person +{ + public string Name { get; set; } + public int Age { get; set; } + + public static Person Deserialize(Stream json) + { + var serializer = new DataContractJsonSerializer(typeof(Person)); + return (Person)serializer.ReadObject(json); + } +} + +``` +### Run the example + +Lastly to run the example: + +``` +$ fission env create --name dotnet --image fission/dotnet-env + +$ fission function create --name httpbody --env dotnet --code /tmp/func.cs + +$ fission route create --method GET --url /http_body --function httpbody + +$ curl -XPOST "http://$FISSION_ROUTER/http_body" -d '{ "Name":"Arthur", "Age":42}' +Hello, my name is Arthur and I am 42 years old. + +``` + + ## Developing/debugging the enviroment locally The easiest way to debug the environment is to open the directory in diff --git a/environments/dotnet/project.json b/environments/dotnet/project.json index 2c1ea729..d4b6cb83 100755 --- a/environments/dotnet/project.json +++ b/environments/dotnet/project.json @@ -1,24 +1,24 @@ { - "version": "1.0.0-*", - "buildOptions": { - "emitEntryPoint": true, - "outputName": "fission-dotnet" - }, - - "dependencies": { - "Microsoft.NETCore.App": { - "version": "1.1.0", - "type": "platform" - }, - "Microsoft.AspNetCore.Server.Kestrel": "1.0.0", - "Microsoft.AspNetCore.Owin": "1.0.0", - "Nancy": "2.0.0-barneyrubble", - "Microsoft.CodeAnalysis.CSharp": "1.3.0-*", - "System.Runtime.Loader": "4.0.0-*", + "version": "1.0.0-*", + "buildOptions": { + "emitEntryPoint": true, + "outputName": "fission-dotnet" }, - "frameworks": { - "netcoreapp1.0": { - "imports": "dnxcore50" + "frameworks": { + "netcoreapp1.0": { + "dependencies": { + "Microsoft.NETCore.App": { + "version": "1.1.0", + "type": "platform" + }, + "Microsoft.AspNetCore.Server.Kestrel": "1.0.0", + "Microsoft.AspNetCore.Owin": "1.0.0", + "Nancy": "2.0.0-barneyrubble", + "Microsoft.CodeAnalysis.CSharp": "1.3.0-*", + "System.Runtime.Loader": "4.0.0-*", + "System.Runtime.Serialization.Json": "4.0.2" + }, + "imports": "netstandard1.3" + } } - } } \ No newline at end of file diff --git a/examples/dotnet/arguments.cs b/examples/dotnet/arguments.cs new file mode 100644 index 00000000..a39e0421 --- /dev/null +++ b/examples/dotnet/arguments.cs @@ -0,0 +1,11 @@ +using System; +using Fission.DotNetCore.Api; + +public class FissionFunction +{ + public string Execute(FissionContext context){ + var x = Convert.ToInt32(context.Arguments["x"]); + var y = Convert.ToInt32(context.Arguments["y"]); + return (x+y).ToString(); + } + diff --git a/examples/dotnet/helloworld.cs b/examples/dotnet/helloworld.cs new file mode 100644 index 00000000..cae5a7e9 --- /dev/null +++ b/examples/dotnet/helloworld.cs @@ -0,0 +1,9 @@ +using Fission.DotNetCore.Api; + +public class FissionFunction +{ + public string Execute(FissionContext context) + { + return "Hello World!"; + } +} diff --git a/examples/dotnet/requestbody.cs b/examples/dotnet/requestbody.cs new file mode 100644 index 00000000..c4be5f44 --- /dev/null +++ b/examples/dotnet/requestbody.cs @@ -0,0 +1,24 @@ +using System.IO; +using System.Runtime.Serialization.Json; +using Fission.DotNetCore.Api; + +public class FissionFunction +{ + public string Execute(FissionContext context) + { + var person = Person.Deserialize(context.Request.Body); + return $"Hello, my name is {person.Name} and I am {person.Age} years old."; + } +} + +public class Person +{ + public string Name { get; set; } + public int Age { get; set; } + + public static Person Deserialize(Stream json) + { + var serializer = new DataContractJsonSerializer(typeof(Person)); + return (Person)serializer.ReadObject(json); + } +} diff --git a/examples/dotnet/requestheaders.cs b/examples/dotnet/requestheaders.cs new file mode 100644 index 00000000..8e44f2f7 --- /dev/null +++ b/examples/dotnet/requestheaders.cs @@ -0,0 +1,17 @@ +using System; +using Fission.DotNetCore.Api; + +public class FissionFunction +{ + public string Execute(FissionContext context){ + var buffer = new System.Text.StringBuilder(); + foreach(var header in context.Request.Headers){ + buffer.AppendLine(header.Key); + foreach(var item in header.Value){ + buffer.AppendLine($"\t{item}"); + } + } + buffer.AppendLine($"Url: {context.Request.Url}, method: {context.Request.Method}"); + return buffer.ToString(); + } +}