├── .dockerignore ├── .gitignore ├── README.md ├── csharp-httprequest.sln └── template └── csharp-httprequest ├── Dockerfile ├── Program.cs ├── Startup.cs ├── function ├── .gitignore ├── Function.csproj └── FunctionHandler.cs ├── root.csproj └── template.yml /.dockerignore: -------------------------------------------------------------------------------- 1 | bin 2 | obj 3 | published -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # File created using '.gitignore Generator' for Visual Studio Code: https://bit.ly/vscode-gig 2 | 3 | # Created by https://www.gitignore.io/api/visualstudiocode,visualstudio 4 | # Edit at https://www.gitignore.io/?templates=visualstudiocode,visualstudio 5 | 6 | ### VisualStudioCode ### 7 | .vscode/* 8 | !.vscode/settings.json 9 | !.vscode/tasks.json 10 | !.vscode/launch.json 11 | !.vscode/extensions.json 12 | 13 | ### VisualStudioCode Patch ### 14 | # Ignore all local history of files 15 | .history 16 | 17 | ### VisualStudio ### 18 | ## Ignore Visual Studio temporary files, build results, and 19 | ## files generated by popular Visual Studio add-ons. 20 | ## 21 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 22 | 23 | # User-specific files 24 | *.rsuser 25 | *.suo 26 | *.user 27 | *.userosscache 28 | *.sln.docstates 29 | 30 | # User-specific files (MonoDevelop/Xamarin Studio) 31 | *.userprefs 32 | 33 | # Build results 34 | [Dd]ebug/ 35 | [Dd]ebugPublic/ 36 | [Rr]elease/ 37 | [Rr]eleases/ 38 | x64/ 39 | x86/ 40 | [Aa][Rr][Mm]/ 41 | [Aa][Rr][Mm]64/ 42 | bld/ 43 | [Bb]in/ 44 | [Oo]bj/ 45 | [Ll]og/ 46 | 47 | # Visual Studio 2015/2017 cache/options directory 48 | .vs/ 49 | # Uncomment if you have tasks that create the project's static files in wwwroot 50 | #wwwroot/ 51 | 52 | # Visual Studio 2017 auto generated files 53 | Generated\ Files/ 54 | 55 | # MSTest test Results 56 | [Tt]est[Rr]esult*/ 57 | [Bb]uild[Ll]og.* 58 | 59 | # NUNIT 60 | *.VisualState.xml 61 | TestResult.xml 62 | 63 | # Build Results of an ATL Project 64 | [Dd]ebugPS/ 65 | [Rr]eleasePS/ 66 | dlldata.c 67 | 68 | # Benchmark Results 69 | BenchmarkDotNet.Artifacts/ 70 | 71 | # .NET Core 72 | project.lock.json 73 | project.fragment.lock.json 74 | artifacts/ 75 | 76 | # StyleCop 77 | StyleCopReport.xml 78 | 79 | # Files built by Visual Studio 80 | *_i.c 81 | *_p.c 82 | *_h.h 83 | *.ilk 84 | *.meta 85 | *.obj 86 | *.iobj 87 | *.pch 88 | *.pdb 89 | *.ipdb 90 | *.pgc 91 | *.pgd 92 | *.rsp 93 | *.sbr 94 | *.tlb 95 | *.tli 96 | *.tlh 97 | *.tmp 98 | *.tmp_proj 99 | *_wpftmp.csproj 100 | *.log 101 | *.vspscc 102 | *.vssscc 103 | .builds 104 | *.pidb 105 | *.svclog 106 | *.scc 107 | 108 | # Chutzpah Test files 109 | _Chutzpah* 110 | 111 | # Visual C++ cache files 112 | ipch/ 113 | *.aps 114 | *.ncb 115 | *.opendb 116 | *.opensdf 117 | *.sdf 118 | *.cachefile 119 | *.VC.db 120 | *.VC.VC.opendb 121 | 122 | # Visual Studio profiler 123 | *.psess 124 | *.vsp 125 | *.vspx 126 | *.sap 127 | 128 | # Visual Studio Trace Files 129 | *.e2e 130 | 131 | # TFS 2012 Local Workspace 132 | $tf/ 133 | 134 | # Guidance Automation Toolkit 135 | *.gpState 136 | 137 | # ReSharper is a .NET coding add-in 138 | _ReSharper*/ 139 | *.[Rr]e[Ss]harper 140 | *.DotSettings.user 141 | 142 | # JustCode is a .NET coding add-in 143 | .JustCode 144 | 145 | # TeamCity is a build add-in 146 | _TeamCity* 147 | 148 | # DotCover is a Code Coverage Tool 149 | *.dotCover 150 | 151 | # AxoCover is a Code Coverage Tool 152 | .axoCover/* 153 | !.axoCover/settings.json 154 | 155 | # Visual Studio code coverage results 156 | *.coverage 157 | *.coveragexml 158 | 159 | # NCrunch 160 | _NCrunch_* 161 | .*crunch*.local.xml 162 | nCrunchTemp_* 163 | 164 | # MightyMoose 165 | *.mm.* 166 | AutoTest.Net/ 167 | 168 | # Web workbench (sass) 169 | .sass-cache/ 170 | 171 | # Installshield output folder 172 | [Ee]xpress/ 173 | 174 | # DocProject is a documentation generator add-in 175 | DocProject/buildhelp/ 176 | DocProject/Help/*.HxT 177 | DocProject/Help/*.HxC 178 | DocProject/Help/*.hhc 179 | DocProject/Help/*.hhk 180 | DocProject/Help/*.hhp 181 | DocProject/Help/Html2 182 | DocProject/Help/html 183 | 184 | # Click-Once directory 185 | publish/ 186 | 187 | # Publish Web Output 188 | *.[Pp]ublish.xml 189 | *.azurePubxml 190 | # Note: Comment the next line if you want to checkin your web deploy settings, 191 | # but database connection strings (with potential passwords) will be unencrypted 192 | *.pubxml 193 | *.publishproj 194 | 195 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 196 | # checkin your Azure Web App publish settings, but sensitive information contained 197 | # in these scripts will be unencrypted 198 | PublishScripts/ 199 | 200 | # NuGet Packages 201 | *.nupkg 202 | # The packages folder can be ignored because of Package Restore 203 | **/[Pp]ackages/* 204 | # except build/, which is used as an MSBuild target. 205 | !**/[Pp]ackages/build/ 206 | # Uncomment if necessary however generally it will be regenerated when needed 207 | #!**/[Pp]ackages/repositories.config 208 | # NuGet v3's project.json files produces more ignorable files 209 | *.nuget.props 210 | *.nuget.targets 211 | 212 | # Microsoft Azure Build Output 213 | csx/ 214 | *.build.csdef 215 | 216 | # Microsoft Azure Emulator 217 | ecf/ 218 | rcf/ 219 | 220 | # Windows Store app package directories and files 221 | AppPackages/ 222 | BundleArtifacts/ 223 | Package.StoreAssociation.xml 224 | _pkginfo.txt 225 | *.appx 226 | 227 | # Visual Studio cache files 228 | # files ending in .cache can be ignored 229 | *.[Cc]ache 230 | # but keep track of directories ending in .cache 231 | !*.[Cc]ache/ 232 | 233 | # Others 234 | ClientBin/ 235 | ~$* 236 | *~ 237 | *.dbmdl 238 | *.dbproj.schemaview 239 | *.jfm 240 | *.pfx 241 | *.publishsettings 242 | orleans.codegen.cs 243 | 244 | # Including strong name files can present a security risk 245 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 246 | #*.snk 247 | 248 | # Since there are multiple workflows, uncomment next line to ignore bower_components 249 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 250 | #bower_components/ 251 | # ASP.NET Core default setup: bower directory is configured as wwwroot/lib/ and bower restore is true 252 | **/wwwroot/lib/ 253 | 254 | # RIA/Silverlight projects 255 | Generated_Code/ 256 | 257 | # Backup & report files from converting an old project file 258 | # to a newer Visual Studio version. Backup files are not needed, 259 | # because we have git ;-) 260 | _UpgradeReport_Files/ 261 | Backup*/ 262 | UpgradeLog*.XML 263 | UpgradeLog*.htm 264 | ServiceFabricBackup/ 265 | *.rptproj.bak 266 | 267 | # SQL Server files 268 | *.mdf 269 | *.ldf 270 | *.ndf 271 | 272 | # Business Intelligence projects 273 | *.rdl.data 274 | *.bim.layout 275 | *.bim_*.settings 276 | *.rptproj.rsuser 277 | 278 | # Microsoft Fakes 279 | FakesAssemblies/ 280 | 281 | # GhostDoc plugin setting file 282 | *.GhostDoc.xml 283 | 284 | # Node.js Tools for Visual Studio 285 | .ntvs_analysis.dat 286 | node_modules/ 287 | 288 | # Visual Studio 6 build log 289 | *.plg 290 | 291 | # Visual Studio 6 workspace options file 292 | *.opt 293 | 294 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 295 | *.vbw 296 | 297 | # Visual Studio LightSwitch build output 298 | **/*.HTMLClient/GeneratedArtifacts 299 | **/*.DesktopClient/GeneratedArtifacts 300 | **/*.DesktopClient/ModelManifest.xml 301 | **/*.Server/GeneratedArtifacts 302 | **/*.Server/ModelManifest.xml 303 | _Pvt_Extensions 304 | 305 | # Paket dependency manager 306 | .paket/paket.exe 307 | paket-files/ 308 | 309 | # FAKE - F# Make 310 | .fake/ 311 | 312 | # JetBrains Rider 313 | .idea/ 314 | *.sln.iml 315 | 316 | # CodeRush personal settings 317 | .cr/personal 318 | 319 | # Python Tools for Visual Studio (PTVS) 320 | __pycache__/ 321 | *.pyc 322 | 323 | # Cake - Uncomment if you are using it 324 | # tools/** 325 | # !tools/packages.config 326 | 327 | # Tabs Studio 328 | *.tss 329 | 330 | # Telerik's JustMock configuration file 331 | *.jmconfig 332 | 333 | # BizTalk build output 334 | *.btp.cs 335 | *.btm.cs 336 | *.odx.cs 337 | *.xsd.cs 338 | 339 | # OpenCover UI analysis results 340 | OpenCover/ 341 | 342 | # Azure Stream Analytics local run output 343 | ASALocalRun/ 344 | 345 | # MSBuild Binary and Structured Log 346 | *.binlog 347 | 348 | # NVidia Nsight GPU debugger configuration file 349 | *.nvuser 350 | 351 | # MFractors (Xamarin productivity tool) working folder 352 | .mfractor/ 353 | 354 | # Local History for Visual Studio 355 | .localhistory/ 356 | 357 | # End of https://www.gitignore.io/api/visualstudiocode,visualstudio 358 | 359 | # Custom rules (everything added below won't be overriden by 'Generate .gitignore File' if you use 'Update' option) 360 | 361 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # OpenFaaS C# HTTP Template 2 | 3 | This repository contains the template for OpenFaaS using the upgraded `of-watchdog` which allows for higher throughput. 4 | 5 | ``` 6 | $ faas template store pull csharp-httprequest 7 | $ faas new --list 8 | Languages available as templates: 9 | - csharp-httprequest 10 | ``` 11 | 12 | This template uses a middleware handler in an ASPNET Core Web API. This allows additional context available in the request (by providing the full body to the handler) and more control over the response by passing it back to the HTTP reponse context. 13 | 14 | ## Using the template 15 | First, pull the template with the faas CLI and create a new function: 16 | 17 | ``` 18 | $ faas template store pull csharp-httprequest 19 | $ faas-cli new --lang csharp-httprequest 20 | ``` 21 | 22 | In the directory that was created, using the name of you function, you'll find `FunctionHandler.cs`. It will look like this: 23 | 24 | ``` csharp 25 | using Microsoft.AspNetCore.Http; 26 | using System.IO; 27 | using System.Threading.Tasks; 28 | 29 | namespace Function 30 | { 31 | public class FunctionHandler 32 | { 33 | public async Task<(int, string)> Handle(HttpRequest request) 34 | { 35 | var reader = new StreamReader(request.Body); 36 | var input = await reader.ReadToEndAsync(); 37 | 38 | return (200, $"Hello! Your input was {input}"); 39 | } 40 | } 41 | } 42 | ``` 43 | 44 | This is a simple implementation of a hello-world function. 45 | 46 | You are able to add packages to your function using the `dotnet add package` syntax. The packages will be added to your final function's container automatically. 47 | 48 | For example, you could add the popular `Newtonsoft.JSON` package for formatting JSON objects. 49 | 50 | ```csharp 51 | using Microsoft.AspNetCore.Http; 52 | using System.Threading.Tasks; 53 | using Newtonsoft.Json; 54 | 55 | namespace Function 56 | { 57 | public class SampleResponse 58 | { 59 | public string FunctionStatus { get; set; } 60 | } 61 | 62 | public class FunctionHandler 63 | { 64 | public Task<(int, string)> Handle(HttpRequest request) 65 | { 66 | var res = new SampleResponse(); 67 | res.FunctionStatus = "Success"; 68 | 69 | var output = JsonConvert.SerializeObject(res); 70 | 71 | return Task.FromResult((200, output)); 72 | } 73 | } 74 | } 75 | ``` -------------------------------------------------------------------------------- /csharp-httprequest.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.27703.2035 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Function", "template\csharp-httprequest\function\Function.csproj", "{7A443F1C-78ED-416E-9625-0CAD4B63D7CA}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "root", "template\csharp-httprequest\root.csproj", "{132C9C0D-0AF1-4D73-91B0-5C072B1B553E}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Release|Any CPU = Release|Any CPU 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {7A443F1C-78ED-416E-9625-0CAD4B63D7CA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 17 | {7A443F1C-78ED-416E-9625-0CAD4B63D7CA}.Debug|Any CPU.Build.0 = Debug|Any CPU 18 | {7A443F1C-78ED-416E-9625-0CAD4B63D7CA}.Release|Any CPU.ActiveCfg = Release|Any CPU 19 | {7A443F1C-78ED-416E-9625-0CAD4B63D7CA}.Release|Any CPU.Build.0 = Release|Any CPU 20 | {132C9C0D-0AF1-4D73-91B0-5C072B1B553E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {132C9C0D-0AF1-4D73-91B0-5C072B1B553E}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {132C9C0D-0AF1-4D73-91B0-5C072B1B553E}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {132C9C0D-0AF1-4D73-91B0-5C072B1B553E}.Release|Any CPU.Build.0 = Release|Any CPU 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {D19A35C8-5F1E-4B8E-B82C-C6A548B5E62C} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /template/csharp-httprequest/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:3.8 as watchdog 2 | 3 | RUN apk --no-cache add curl \ 4 | && echo "Pulling watchdog binary from Github." \ 5 | && curl -sSL https://github.com/openfaas-incubator/of-watchdog/releases/download/0.5.1/of-watchdog > /usr/bin/fwatchdog \ 6 | && chmod +x /usr/bin/fwatchdog \ 7 | && cp /usr/bin/fwatchdog /home/app \ 8 | && apk del curl --no-cache 9 | 10 | FROM mcr.microsoft.com/dotnet/core/sdk:2.2 as builder 11 | 12 | # Supress collection of data. 13 | ENV DOTNET_CLI_TELEMETRY_OPTOUT 1 14 | 15 | # Optimize for Docker builder caching by adding projects first. 16 | 17 | RUN mkdir -p /home/app/function 18 | WORKDIR /home/app/function 19 | COPY ./function/Function.csproj . 20 | 21 | WORKDIR /home/app/src/ 22 | COPY ./root.csproj . 23 | RUN dotnet restore ./root.csproj 24 | 25 | COPY . . 26 | 27 | RUN dotnet publish -c release -o published 28 | 29 | FROM mcr.microsoft.com/dotnet/core/aspnet:2.2 30 | 31 | COPY --from=watchdog /usr/bin/fwatchdog /usr/bin/ 32 | 33 | # Create a non-root user 34 | RUN addgroup --system app \ 35 | && adduser --system --ingroup app app 36 | 37 | WORKDIR /home/app/ 38 | COPY --from=builder /home/app/src/published . 39 | RUN chown app:app -R /home/app 40 | 41 | USER app 42 | 43 | ENV fprocess="dotnet ./root.dll" 44 | ENV cgi_headers="true" 45 | ENV mode="http" 46 | ENV upstream_url="http://localhost:5000" 47 | EXPOSE 8080 48 | 49 | HEALTHCHECK --interval=3s CMD [ -e /tmp/.lock ] || exit 1 50 | 51 | CMD ["fwatchdog"] -------------------------------------------------------------------------------- /template/csharp-httprequest/Program.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore; 2 | using Microsoft.AspNetCore.Hosting; 3 | 4 | public class Program 5 | { 6 | public static void Main(string[] args) => CreateWebHostBuilder(args).Build().Run(); 7 | 8 | public static IWebHostBuilder CreateWebHostBuilder(string[] args) => 9 | WebHost.CreateDefaultBuilder(args) 10 | .UseStartup() 11 | .UseUrls("http://localhost:5000"); 12 | } 13 | -------------------------------------------------------------------------------- /template/csharp-httprequest/Startup.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.DependencyInjection; 2 | using Microsoft.AspNetCore.Builder; 3 | using Microsoft.AspNetCore.Hosting; 4 | using Function; 5 | using System; 6 | using Microsoft.AspNetCore.Http; 7 | 8 | public class Startup 9 | { 10 | public void ConfigureServices(IServiceCollection services) 11 | { 12 | } 13 | 14 | public void Configure(IApplicationBuilder app, IHostingEnvironment env) 15 | { 16 | app.Run(async (context) => 17 | { 18 | if (context.Request.Path != "/") 19 | { 20 | context.Response.StatusCode = 404; 21 | await context.Response.WriteAsync("404 - Not Found"); 22 | return; 23 | } 24 | 25 | if (context.Request.Method != "POST") 26 | { 27 | context.Response.StatusCode = 405; 28 | await context.Response.WriteAsync("405 - Only POST method allowed"); 29 | return; 30 | } 31 | 32 | try 33 | { 34 | var (status, text) = await new FunctionHandler().Handle(context.Request); 35 | context.Response.StatusCode = status; 36 | if (!string.IsNullOrEmpty(text)) 37 | await context.Response.WriteAsync(text); 38 | } 39 | catch (NotImplementedException nie) 40 | { 41 | context.Response.StatusCode = 501; 42 | await context.Response.WriteAsync(nie.ToString()); 43 | } 44 | catch (Exception ex) 45 | { 46 | context.Response.StatusCode = 500; 47 | await context.Response.WriteAsync(ex.ToString()); 48 | } 49 | }); 50 | } 51 | } -------------------------------------------------------------------------------- /template/csharp-httprequest/function/.gitignore: -------------------------------------------------------------------------------- 1 | bin/ 2 | obj/ 3 | .nuget/ 4 | .dotnet/ 5 | .templateengine/ -------------------------------------------------------------------------------- /template/csharp-httprequest/function/Function.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | netstandard2.0 4 | false 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /template/csharp-httprequest/function/FunctionHandler.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Http; 2 | using System.IO; 3 | using System.Threading.Tasks; 4 | 5 | namespace Function 6 | { 7 | public class FunctionHandler 8 | { 9 | public async Task<(int, string)> Handle(HttpRequest request) 10 | { 11 | var reader = new StreamReader(request.Body); 12 | var input = await reader.ReadToEndAsync(); 13 | 14 | return (200, $"Hello! Your input was {input}"); 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /template/csharp-httprequest/root.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | netcoreapp2.2 6 | false 7 | false 8 | false 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /template/csharp-httprequest/template.yml: -------------------------------------------------------------------------------- 1 | language: csharp-httprequest 2 | fprocess: dotnet ./root.dll --------------------------------------------------------------------------------