├── .gitignore ├── 1-portal-timer ├── function.json └── run.fsx ├── 10-app ├── .gitattributes ├── .gitignore ├── .vscode │ ├── launch.json │ └── tasks.json ├── FunctionGraph.png ├── LICENSE ├── Landing │ └── function.json ├── Poll.fs ├── PollApp.fsproj ├── Results │ └── function.json ├── Send │ └── function.json ├── Sentiment │ └── function.json ├── Twitter │ └── function.json ├── host.json └── local.settings.json ├── 11-app-attributes ├── .gitattributes ├── .gitignore ├── .vscode │ ├── launch.json │ └── tasks.json ├── LICENSE ├── Poll.fs ├── PollApp.fsproj ├── host.json └── local.settings.json ├── 12-durable ├── .gitattributes ├── .gitignore ├── .vscode │ ├── launch.json │ └── tasks.json ├── BackupSiteContent.fs ├── Counter.fs ├── DurableFSharp.fsproj ├── HelloSequence.fs ├── HttpStart.fs ├── HttpSyncStart.fs ├── PhoneVerification.fs ├── host.json └── local.settings.json ├── 13-fsharp-from-csharp ├── CSharpFunctionApp │ ├── CSharpFunctionApp.csproj │ ├── CSharpFunctions.cs │ ├── host.json │ └── local.settings.json ├── FSharpLibrary │ ├── FSharpLibrary.fsproj │ └── Library.fs └── FsharpFromCsharpFunction.sln ├── 2-portal-http ├── function.json └── run.fsx ├── 3-portal-http-html ├── function.json ├── html │ ├── awesome.html │ └── hello.html └── run.fsx ├── 4-cli-http ├── .gitignore ├── cli-http │ ├── function.json │ ├── project.json │ ├── run.fsx │ └── sample.dat └── host.json ├── 5-precompiled-full-framework ├── .gitattributes ├── .gitignore ├── .vscode │ ├── launch.json │ └── tasks.json ├── LICENSE ├── PrecompiledApp.fsproj ├── PrecompiledHttp │ ├── PrecompiledHttp.fs │ └── function.json ├── host.json └── local.settings.json ├── 5-precompiled ├── .gitattributes ├── .gitignore ├── .vscode │ ├── launch.json │ └── tasks.json ├── PrecompiledApp.fsproj ├── PrecompiledHttp │ ├── PrecompiledHttp.fs │ └── function.json ├── host.json └── local.settings.json ├── 6-precompiled-timer ├── .vscode │ ├── launch.json │ └── tasks.json ├── Hello │ └── function.json ├── HelloFunctions.fsproj ├── Library.fs ├── host.json └── local.settings.json ├── 6b-precompiled-http-to-service-bus-topic ├── FromHttpTriggerToServiceBusTopic.fs ├── FromHttpTriggerToServiceBusTopic.fsproj ├── README.MD ├── host.json ├── local.settings.json └── proxies.json ├── 7-suave ├── .gitignore ├── .vscode │ ├── launch.json │ └── tasks.json ├── LICENSE ├── README.md ├── SuaveApp.fsproj ├── SuaveHttp │ ├── Adapter │ │ ├── Context.fs │ │ ├── Request.fs │ │ └── Response.fs │ ├── SuaveHttp.fs │ └── function.json ├── host.json └── local.settings.json ├── 8-paket ├── .paket │ ├── Paket.Restore.targets │ ├── paket.bootstrapper.exe │ ├── paket.exe │ └── paket.targets ├── .vscode │ ├── launch.json │ └── tasks.json ├── PaketFunctions.sln ├── PaketFunctions │ ├── PaketFunctions.fsproj │ ├── PaketHttp │ │ ├── PaketHttp.fs │ │ └── function.json │ ├── host.json │ ├── local.settings.json │ └── paket.references └── paket.dependencies ├── 9-attributes ├── .gitattributes ├── .gitignore ├── .vscode │ ├── launch.json │ └── tasks.json ├── AttributeBasedApp.fsproj ├── LICENSE ├── PrecompiledHttp.fs ├── host.json └── local.settings.json ├── LICENSE ├── README.md └── tool-function-graph-gen ├── App.config ├── AssemblyInfo.fs ├── AzureFunctionGraphGen.fsproj ├── Program.fs └── packages.config /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.suo 8 | *.user 9 | *.userosscache 10 | *.sln.docstates 11 | 12 | # User-specific files (MonoDevelop/Xamarin Studio) 13 | *.userprefs 14 | 15 | # Build results 16 | [Dd]ebug/ 17 | [Dd]ebugPublic/ 18 | [Rr]elease/ 19 | [Rr]eleases/ 20 | x64/ 21 | x86/ 22 | bld/ 23 | [Bb]in/ 24 | [Oo]bj/ 25 | [Ll]og/ 26 | 27 | # Visual Studio 2015 cache/options directory 28 | .vs/ 29 | # Uncomment if you have tasks that create the project's static files in wwwroot 30 | #wwwroot/ 31 | 32 | # MSTest test Results 33 | [Tt]est[Rr]esult*/ 34 | [Bb]uild[Ll]og.* 35 | 36 | # NUNIT 37 | *.VisualState.xml 38 | TestResult.xml 39 | 40 | # Build Results of an ATL Project 41 | [Dd]ebugPS/ 42 | [Rr]eleasePS/ 43 | dlldata.c 44 | 45 | # .NET Core 46 | project.lock.json 47 | project.fragment.lock.json 48 | artifacts/ 49 | **/Properties/launchSettings.json 50 | 51 | *_i.c 52 | *_p.c 53 | *_i.h 54 | *.ilk 55 | *.meta 56 | *.obj 57 | *.pch 58 | *.pdb 59 | *.pgc 60 | *.pgd 61 | *.rsp 62 | *.sbr 63 | *.tlb 64 | *.tli 65 | *.tlh 66 | *.tmp 67 | *.tmp_proj 68 | *.log 69 | *.vspscc 70 | *.vssscc 71 | .builds 72 | *.pidb 73 | *.svclog 74 | *.scc 75 | 76 | # Chutzpah Test files 77 | _Chutzpah* 78 | 79 | # Visual C++ cache files 80 | ipch/ 81 | *.aps 82 | *.ncb 83 | *.opendb 84 | *.opensdf 85 | *.sdf 86 | *.cachefile 87 | *.VC.db 88 | *.VC.VC.opendb 89 | 90 | # Visual Studio profiler 91 | *.psess 92 | *.vsp 93 | *.vspx 94 | *.sap 95 | 96 | # TFS 2012 Local Workspace 97 | $tf/ 98 | 99 | # Guidance Automation Toolkit 100 | *.gpState 101 | 102 | # ReSharper is a .NET coding add-in 103 | _ReSharper*/ 104 | *.[Rr]e[Ss]harper 105 | *.DotSettings.user 106 | 107 | # JustCode is a .NET coding add-in 108 | .JustCode 109 | 110 | # TeamCity is a build add-in 111 | _TeamCity* 112 | 113 | # DotCover is a Code Coverage Tool 114 | *.dotCover 115 | 116 | # Visual Studio code coverage results 117 | *.coverage 118 | *.coveragexml 119 | 120 | # NCrunch 121 | _NCrunch_* 122 | .*crunch*.local.xml 123 | nCrunchTemp_* 124 | 125 | # MightyMoose 126 | *.mm.* 127 | AutoTest.Net/ 128 | 129 | # Web workbench (sass) 130 | .sass-cache/ 131 | 132 | # Installshield output folder 133 | [Ee]xpress/ 134 | 135 | # DocProject is a documentation generator add-in 136 | DocProject/buildhelp/ 137 | DocProject/Help/*.HxT 138 | DocProject/Help/*.HxC 139 | DocProject/Help/*.hhc 140 | DocProject/Help/*.hhk 141 | DocProject/Help/*.hhp 142 | DocProject/Help/Html2 143 | DocProject/Help/html 144 | 145 | # Click-Once directory 146 | publish/ 147 | 148 | # Publish Web Output 149 | *.[Pp]ublish.xml 150 | *.azurePubxml 151 | # TODO: Comment the next line if you want to checkin your web deploy settings 152 | # but database connection strings (with potential passwords) will be unencrypted 153 | *.pubxml 154 | *.publishproj 155 | 156 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 157 | # checkin your Azure Web App publish settings, but sensitive information contained 158 | # in these scripts will be unencrypted 159 | PublishScripts/ 160 | 161 | # NuGet Packages 162 | *.nupkg 163 | # The packages folder can be ignored because of Package Restore 164 | **/packages/* 165 | # except build/, which is used as an MSBuild target. 166 | !**/packages/build/ 167 | # Uncomment if necessary however generally it will be regenerated when needed 168 | #!**/packages/repositories.config 169 | # NuGet v3's project.json files produces more ignorable files 170 | *.nuget.props 171 | *.nuget.targets 172 | 173 | # Microsoft Azure Build Output 174 | csx/ 175 | *.build.csdef 176 | 177 | # Microsoft Azure Emulator 178 | ecf/ 179 | rcf/ 180 | 181 | # Windows Store app package directories and files 182 | AppPackages/ 183 | BundleArtifacts/ 184 | Package.StoreAssociation.xml 185 | _pkginfo.txt 186 | 187 | # Visual Studio cache files 188 | # files ending in .cache can be ignored 189 | *.[Cc]ache 190 | # but keep track of directories ending in .cache 191 | !*.[Cc]ache/ 192 | 193 | # Others 194 | ClientBin/ 195 | ~$* 196 | *~ 197 | *.dbmdl 198 | *.dbproj.schemaview 199 | *.jfm 200 | *.pfx 201 | *.publishsettings 202 | orleans.codegen.cs 203 | 204 | # Since there are multiple workflows, uncomment next line to ignore bower_components 205 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 206 | #bower_components/ 207 | 208 | # RIA/Silverlight projects 209 | Generated_Code/ 210 | 211 | # Backup & report files from converting an old project file 212 | # to a newer Visual Studio version. Backup files are not needed, 213 | # because we have git ;-) 214 | _UpgradeReport_Files/ 215 | Backup*/ 216 | UpgradeLog*.XML 217 | UpgradeLog*.htm 218 | 219 | # SQL Server files 220 | *.mdf 221 | *.ldf 222 | *.ndf 223 | 224 | # Business Intelligence projects 225 | *.rdl.data 226 | *.bim.layout 227 | *.bim_*.settings 228 | 229 | # Microsoft Fakes 230 | FakesAssemblies/ 231 | 232 | # GhostDoc plugin setting file 233 | *.GhostDoc.xml 234 | 235 | # Node.js Tools for Visual Studio 236 | .ntvs_analysis.dat 237 | node_modules/ 238 | 239 | # Typescript v1 declaration files 240 | typings/ 241 | 242 | # Visual Studio 6 build log 243 | *.plg 244 | 245 | # Visual Studio 6 workspace options file 246 | *.opt 247 | 248 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 249 | *.vbw 250 | 251 | # Visual Studio LightSwitch build output 252 | **/*.HTMLClient/GeneratedArtifacts 253 | **/*.DesktopClient/GeneratedArtifacts 254 | **/*.DesktopClient/ModelManifest.xml 255 | **/*.Server/GeneratedArtifacts 256 | **/*.Server/ModelManifest.xml 257 | _Pvt_Extensions 258 | 259 | # Paket dependency manager 260 | .paket/paket.exe 261 | paket-files/ 262 | 263 | # FAKE - F# Make 264 | .fake/ 265 | 266 | # JetBrains Rider 267 | .idea/ 268 | *.sln.iml 269 | 270 | # CodeRush 271 | .cr/ 272 | 273 | # Python Tools for Visual Studio (PTVS) 274 | __pycache__/ 275 | *.pyc 276 | 277 | # Cake - Uncomment if you are using it 278 | # tools/** 279 | # !tools/packages.config 280 | 281 | # Telerik's JustMock configuration file 282 | *.jmconfig 283 | 284 | # BizTalk build output 285 | *.btp.cs 286 | *.btm.cs 287 | *.odx.cs 288 | *.xsd.cs 289 | 290 | # Visual Studio Code 291 | **/.vscode/ -------------------------------------------------------------------------------- /1-portal-timer/function.json: -------------------------------------------------------------------------------- 1 | { 2 | "bindings": [ 3 | { 4 | "name": "myTimer", 5 | "type": "timerTrigger", 6 | "direction": "in", 7 | "schedule": "0 * * * * *" 8 | } 9 | ], 10 | "disabled": false 11 | } -------------------------------------------------------------------------------- /1-portal-timer/run.fsx: -------------------------------------------------------------------------------- 1 | open System 2 | 3 | let minutesSince (d: DateTime) = 4 | (DateTime.Now - d).TotalMinutes 5 | 6 | let run(myTimer: TimerInfo, log: TraceWriter) = 7 | let meetupStart = new DateTime(2017, 11, 8, 19, 0, 0) 8 | 9 | minutesSince meetupStart 10 | |> int 11 | |> sprintf "Our meetup has been running for %d minutes" 12 | |> log.Info -------------------------------------------------------------------------------- /10-app/.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /10-app/.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | bld/ 21 | [Bb]in/ 22 | [Oo]bj/ 23 | [Ll]og/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | project.fragment.lock.json 46 | artifacts/ 47 | 48 | *_i.c 49 | *_p.c 50 | *_i.h 51 | *.ilk 52 | *.meta 53 | *.obj 54 | *.pch 55 | *.pdb 56 | *.pgc 57 | *.pgd 58 | *.rsp 59 | *.sbr 60 | *.tlb 61 | *.tli 62 | *.tlh 63 | *.tmp 64 | *.tmp_proj 65 | *.log 66 | *.vspscc 67 | *.vssscc 68 | .builds 69 | *.pidb 70 | *.svclog 71 | *.scc 72 | 73 | # Chutzpah Test files 74 | _Chutzpah* 75 | 76 | # Visual C++ cache files 77 | ipch/ 78 | *.aps 79 | *.ncb 80 | *.opendb 81 | *.opensdf 82 | *.sdf 83 | *.cachefile 84 | *.VC.db 85 | *.VC.VC.opendb 86 | 87 | # Visual Studio profiler 88 | *.psess 89 | *.vsp 90 | *.vspx 91 | *.sap 92 | 93 | # TFS 2012 Local Workspace 94 | $tf/ 95 | 96 | # Guidance Automation Toolkit 97 | *.gpState 98 | 99 | # ReSharper is a .NET coding add-in 100 | _ReSharper*/ 101 | *.[Rr]e[Ss]harper 102 | *.DotSettings.user 103 | 104 | # JustCode is a .NET coding add-in 105 | .JustCode 106 | 107 | # TeamCity is a build add-in 108 | _TeamCity* 109 | 110 | # DotCover is a Code Coverage Tool 111 | *.dotCover 112 | 113 | # NCrunch 114 | _NCrunch_* 115 | .*crunch*.local.xml 116 | nCrunchTemp_* 117 | 118 | # MightyMoose 119 | *.mm.* 120 | AutoTest.Net/ 121 | 122 | # Web workbench (sass) 123 | .sass-cache/ 124 | 125 | # Installshield output folder 126 | [Ee]xpress/ 127 | 128 | # DocProject is a documentation generator add-in 129 | DocProject/buildhelp/ 130 | DocProject/Help/*.HxT 131 | DocProject/Help/*.HxC 132 | DocProject/Help/*.hhc 133 | DocProject/Help/*.hhk 134 | DocProject/Help/*.hhp 135 | DocProject/Help/Html2 136 | DocProject/Help/html 137 | 138 | # Click-Once directory 139 | publish/ 140 | 141 | # Publish Web Output 142 | *.[Pp]ublish.xml 143 | *.azurePubxml 144 | # TODO: Comment the next line if you want to checkin your web deploy settings 145 | # but database connection strings (with potential passwords) will be unencrypted 146 | #*.pubxml 147 | *.publishproj 148 | 149 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 150 | # checkin your Azure Web App publish settings, but sensitive information contained 151 | # in these scripts will be unencrypted 152 | PublishScripts/ 153 | 154 | # NuGet Packages 155 | *.nupkg 156 | # The packages folder can be ignored because of Package Restore 157 | **/packages/* 158 | # except build/, which is used as an MSBuild target. 159 | !**/packages/build/ 160 | # Uncomment if necessary however generally it will be regenerated when needed 161 | #!**/packages/repositories.config 162 | # NuGet v3's project.json files produces more ignoreable files 163 | *.nuget.props 164 | *.nuget.targets 165 | 166 | # Microsoft Azure Build Output 167 | csx/ 168 | *.build.csdef 169 | 170 | # Microsoft Azure Emulator 171 | ecf/ 172 | rcf/ 173 | 174 | # Windows Store app package directories and files 175 | AppPackages/ 176 | BundleArtifacts/ 177 | Package.StoreAssociation.xml 178 | _pkginfo.txt 179 | 180 | # Visual Studio cache files 181 | # files ending in .cache can be ignored 182 | *.[Cc]ache 183 | # but keep track of directories ending in .cache 184 | !*.[Cc]ache/ 185 | 186 | # Others 187 | ClientBin/ 188 | ~$* 189 | *~ 190 | *.dbmdl 191 | *.dbproj.schemaview 192 | *.jfm 193 | *.pfx 194 | *.publishsettings 195 | node_modules/ 196 | orleans.codegen.cs 197 | 198 | # Since there are multiple workflows, uncomment next line to ignore bower_components 199 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 200 | #bower_components/ 201 | 202 | # RIA/Silverlight projects 203 | Generated_Code/ 204 | 205 | # Backup & report files from converting an old project file 206 | # to a newer Visual Studio version. Backup files are not needed, 207 | # because we have git ;-) 208 | _UpgradeReport_Files/ 209 | Backup*/ 210 | UpgradeLog*.XML 211 | UpgradeLog*.htm 212 | 213 | # SQL Server files 214 | *.mdf 215 | *.ldf 216 | 217 | # Business Intelligence projects 218 | *.rdl.data 219 | *.bim.layout 220 | *.bim_*.settings 221 | 222 | # Microsoft Fakes 223 | FakesAssemblies/ 224 | 225 | # GhostDoc plugin setting file 226 | *.GhostDoc.xml 227 | 228 | # Node.js Tools for Visual Studio 229 | .ntvs_analysis.dat 230 | 231 | # Visual Studio 6 build log 232 | *.plg 233 | 234 | # Visual Studio 6 workspace options file 235 | *.opt 236 | 237 | # Visual Studio LightSwitch build output 238 | **/*.HTMLClient/GeneratedArtifacts 239 | **/*.DesktopClient/GeneratedArtifacts 240 | **/*.DesktopClient/ModelManifest.xml 241 | **/*.Server/GeneratedArtifacts 242 | **/*.Server/ModelManifest.xml 243 | _Pvt_Extensions 244 | 245 | # Paket dependency manager 246 | .paket/paket.exe 247 | paket-files/ 248 | 249 | # FAKE - F# Make 250 | .fake/ 251 | 252 | # JetBrains Rider 253 | .idea/ 254 | *.sln.iml 255 | 256 | # CodeRush 257 | .cr/ 258 | 259 | # Python Tools for Visual Studio (PTVS) 260 | __pycache__/ 261 | *.pyc -------------------------------------------------------------------------------- /10-app/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": ".NET Core Attach", 6 | "type": "coreclr", 7 | "request": "attach", 8 | "preLaunchTask": "run", 9 | "processId": "${command:pickProcess}" 10 | } 11 | ] 12 | } -------------------------------------------------------------------------------- /10-app/.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=733558 3 | // for the documentation about the tasks.json format 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "taskName": "build", 8 | "command": "dotnet build", 9 | "type": "shell", 10 | "group": { 11 | "kind": "build", 12 | "isDefault": true 13 | }, 14 | "presentation": { 15 | "reveal": "silent" 16 | }, 17 | "problemMatcher": "$msCompile" 18 | }, 19 | { 20 | "taskName": "publish", 21 | "command": "dotnet publish", 22 | "dependsOn": "build", 23 | "type": "shell", 24 | "problemMatcher": [] 25 | }, 26 | { 27 | "taskName": "run", 28 | "command": "cd bin\\debug\\netstandard2.0\\publish ; func host start", 29 | "dependsOn": "publish", 30 | "type": "shell", 31 | "problemMatcher": [] 32 | } 33 | ] 34 | } -------------------------------------------------------------------------------- /10-app/FunctionGraph.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mikhailshilkov/azure-functions-fsharp-examples/24501c809b1998ab069ab23802862084505f5390/10-app/FunctionGraph.png -------------------------------------------------------------------------------- /10-app/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Donna Malayeri 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /10-app/Landing/function.json: -------------------------------------------------------------------------------- 1 | { 2 | "bindings": [ 3 | { 4 | "type": "httpTrigger", 5 | "methods": ["get"], 6 | "authLevel": "anonymous", 7 | "name": "req", 8 | "route": "poll" 9 | }, 10 | { 11 | "type": "blob", 12 | "name": "html", 13 | "path": "fsharping/poll.html", 14 | "direction": "in" 15 | } 16 | ], 17 | "scriptFile": "../bin/PollApp.dll", 18 | "entryPoint": "PollApp.Landing.run" 19 | } -------------------------------------------------------------------------------- /10-app/Poll.fs: -------------------------------------------------------------------------------- 1 | namespace PollApp 2 | 3 | open System 4 | open Microsoft.AspNetCore.Mvc 5 | open Microsoft.AspNetCore.Http 6 | open Microsoft.Azure.WebJobs 7 | open Microsoft.Azure.WebJobs.Host 8 | open Microsoft.WindowsAzure.Storage.Table 9 | open Microsoft.Azure.WebJobs.Extensions.Http 10 | 11 | module Utils = 12 | let toOption (n: Nullable<_>) = 13 | if n.HasValue 14 | then Some n.Value 15 | else None 16 | 17 | module Twitter = 18 | 19 | let run(tweet: string, pollResults: ICollector, log: TraceWriter) = 20 | log.Info (sprintf "Tweet: %s" tweet) 21 | pollResults.Add tweet 22 | 23 | 24 | module Landing = 25 | 26 | let run(req: HttpRequest, html: string, log: TraceWriter) = 27 | log.Info("F# HTTP trigger function processed a request." + html) 28 | 29 | ContentResult(Content = html, ContentType = "text/html") 30 | 31 | [] 32 | type PollResult = { 33 | value: string 34 | } 35 | 36 | type SentimentResult() = 37 | inherit TableEntity() 38 | member val Text = "" with get, set 39 | member val Score = Nullable() with get, set 40 | 41 | module Send = 42 | 43 | let run(req: PollResult, pollResults: ICollector, log: TraceWriter) = 44 | log.Info (sprintf "Poll result: %s" req.value) 45 | pollResults.Add req.value 46 | 47 | module Sentiment = 48 | open Microsoft.Azure.CognitiveServices.Language.TextAnalytics 49 | open Microsoft.Azure.CognitiveServices.Language.TextAnalytics.Models 50 | 51 | let run (feedbackText, log: TraceWriter) = 52 | let client = new TextAnalyticsAPI() 53 | client.AzureRegion <- AzureRegions.Westeurope 54 | client.SubscriptionKey <- "65ff5b18c51c4a2ebd4505cbd5fe1e4b" 55 | 56 | let result = client.Sentiment( 57 | MultiLanguageBatchInput( 58 | [| MultiLanguageInput("en", "0", feedbackText) |])) 59 | 60 | let score = 61 | result.Documents 62 | |> Seq.tryHead 63 | |> Option.map (fun x -> x.Score) 64 | |> Option.bind Utils.toOption 65 | 66 | let msg = 67 | match score with 68 | | Some s -> sprintf "Sentiment of %s is %f" feedbackText s 69 | | None -> sprintf "No sentiment for %s" feedbackText 70 | log.Info msg 71 | 72 | let savedScore = 73 | match score with 74 | | Some s -> Nullable(s) 75 | | None -> Nullable() 76 | 77 | SentimentResult(PartitionKey = "default", RowKey = Guid.NewGuid().ToString(), Text = feedbackText, Score = savedScore) 78 | 79 | module Results = 80 | open System.Linq 81 | open Utils 82 | 83 | type Report = { 84 | AverageScore: double 85 | Messages: string list 86 | } 87 | 88 | let run(req: HttpRequest, resultsTable: CloudTable, log: TraceWriter) = 89 | 90 | let sentiments = resultsTable.ExecuteQuerySegmentedAsync(new TableQuery(), null).Result.AsEnumerable() 91 | let averageScore = 92 | sentiments 93 | |> Seq.map (fun r -> r.Score) 94 | |> Seq.choose toOption 95 | |> Seq.average 96 | let messages = sentiments |> Seq.map (fun r -> r.Text) |> List.ofSeq 97 | 98 | log.Info(sprintf "Average score: %f" averageScore) 99 | 100 | ObjectResult({ AverageScore = averageScore; Messages = messages }) 101 | 102 | -------------------------------------------------------------------------------- /10-app/PollApp.fsproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard2.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | PreserveNewest 20 | 21 | 22 | PreserveNewest 23 | 24 | 25 | PreserveNewest 26 | 27 | 28 | PreserveNewest 29 | 30 | 31 | PreserveNewest 32 | 33 | 34 | PreserveNewest 35 | 36 | 37 | PreserveNewest 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /10-app/Results/function.json: -------------------------------------------------------------------------------- 1 | { 2 | "bindings": [ 3 | { 4 | "type": "httpTrigger", 5 | "methods": [ 6 | "get", 7 | "options" 8 | ], 9 | "authLevel": "anonymous", 10 | "name": "req" 11 | }, 12 | { 13 | "type": "table", 14 | "name": "resultsTable", 15 | "tableName": "Sentiment", 16 | "direction": "in" 17 | } 18 | ], 19 | "disabled": false, 20 | "scriptFile": "../bin/PollApp.dll", 21 | "entryPoint": "PollApp.Results.run" 22 | } -------------------------------------------------------------------------------- /10-app/Send/function.json: -------------------------------------------------------------------------------- 1 | { 2 | "bindings": [ 3 | { 4 | "type": "httpTrigger", 5 | "methods": ["post"], 6 | "authLevel": "anonymous", 7 | "name": "req", 8 | "route": "send" 9 | }, 10 | { 11 | "type": "queue", 12 | "name": "pollResults", 13 | "queueName": "poll-item", 14 | "direction": "out" 15 | } 16 | ], 17 | "scriptFile": "../bin/PollApp.dll", 18 | "entryPoint": "PollApp.Send.run" 19 | } -------------------------------------------------------------------------------- /10-app/Sentiment/function.json: -------------------------------------------------------------------------------- 1 | { 2 | "bindings": [ 3 | { 4 | "type": "queueTrigger", 5 | "name": "feedbackText", 6 | "queueName": "poll-item" 7 | }, 8 | { 9 | "type": "table", 10 | "name": "$return", 11 | "tableName": "Sentiment", 12 | "direction": "out" 13 | } 14 | ], 15 | "scriptFile": "../bin/PollApp.dll", 16 | "entryPoint": "PollApp.Sentiment.run" 17 | } -------------------------------------------------------------------------------- /10-app/Twitter/function.json: -------------------------------------------------------------------------------- 1 | { 2 | "bindings": [ 3 | { 4 | "type": "queueTrigger", 5 | "queueName": "tweets", 6 | "name": "tweet" 7 | }, 8 | { 9 | "type": "queue", 10 | "name": "pollResults", 11 | "queueName": "poll-item", 12 | "direction": "out" 13 | } 14 | ], 15 | "disabled": false, 16 | "scriptFile": "../bin/PollApp.dll", 17 | "entryPoint": "PollApp.Twitter.run" 18 | } -------------------------------------------------------------------------------- /10-app/host.json: -------------------------------------------------------------------------------- 1 | { 2 | } -------------------------------------------------------------------------------- /10-app/local.settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "IsEncrypted": false, 3 | "Values": { 4 | "AzureWebJobsStorage": "UseDevelopmentStorage=true" 5 | } 6 | } -------------------------------------------------------------------------------- /11-app-attributes/.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /11-app-attributes/.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | bld/ 21 | [Bb]in/ 22 | [Oo]bj/ 23 | [Ll]og/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | project.fragment.lock.json 46 | artifacts/ 47 | 48 | *_i.c 49 | *_p.c 50 | *_i.h 51 | *.ilk 52 | *.meta 53 | *.obj 54 | *.pch 55 | *.pdb 56 | *.pgc 57 | *.pgd 58 | *.rsp 59 | *.sbr 60 | *.tlb 61 | *.tli 62 | *.tlh 63 | *.tmp 64 | *.tmp_proj 65 | *.log 66 | *.vspscc 67 | *.vssscc 68 | .builds 69 | *.pidb 70 | *.svclog 71 | *.scc 72 | 73 | # Chutzpah Test files 74 | _Chutzpah* 75 | 76 | # Visual C++ cache files 77 | ipch/ 78 | *.aps 79 | *.ncb 80 | *.opendb 81 | *.opensdf 82 | *.sdf 83 | *.cachefile 84 | *.VC.db 85 | *.VC.VC.opendb 86 | 87 | # Visual Studio profiler 88 | *.psess 89 | *.vsp 90 | *.vspx 91 | *.sap 92 | 93 | # TFS 2012 Local Workspace 94 | $tf/ 95 | 96 | # Guidance Automation Toolkit 97 | *.gpState 98 | 99 | # ReSharper is a .NET coding add-in 100 | _ReSharper*/ 101 | *.[Rr]e[Ss]harper 102 | *.DotSettings.user 103 | 104 | # JustCode is a .NET coding add-in 105 | .JustCode 106 | 107 | # TeamCity is a build add-in 108 | _TeamCity* 109 | 110 | # DotCover is a Code Coverage Tool 111 | *.dotCover 112 | 113 | # NCrunch 114 | _NCrunch_* 115 | .*crunch*.local.xml 116 | nCrunchTemp_* 117 | 118 | # MightyMoose 119 | *.mm.* 120 | AutoTest.Net/ 121 | 122 | # Web workbench (sass) 123 | .sass-cache/ 124 | 125 | # Installshield output folder 126 | [Ee]xpress/ 127 | 128 | # DocProject is a documentation generator add-in 129 | DocProject/buildhelp/ 130 | DocProject/Help/*.HxT 131 | DocProject/Help/*.HxC 132 | DocProject/Help/*.hhc 133 | DocProject/Help/*.hhk 134 | DocProject/Help/*.hhp 135 | DocProject/Help/Html2 136 | DocProject/Help/html 137 | 138 | # Click-Once directory 139 | publish/ 140 | 141 | # Publish Web Output 142 | *.[Pp]ublish.xml 143 | *.azurePubxml 144 | # TODO: Comment the next line if you want to checkin your web deploy settings 145 | # but database connection strings (with potential passwords) will be unencrypted 146 | #*.pubxml 147 | *.publishproj 148 | 149 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 150 | # checkin your Azure Web App publish settings, but sensitive information contained 151 | # in these scripts will be unencrypted 152 | PublishScripts/ 153 | 154 | # NuGet Packages 155 | *.nupkg 156 | # The packages folder can be ignored because of Package Restore 157 | **/packages/* 158 | # except build/, which is used as an MSBuild target. 159 | !**/packages/build/ 160 | # Uncomment if necessary however generally it will be regenerated when needed 161 | #!**/packages/repositories.config 162 | # NuGet v3's project.json files produces more ignoreable files 163 | *.nuget.props 164 | *.nuget.targets 165 | 166 | # Microsoft Azure Build Output 167 | csx/ 168 | *.build.csdef 169 | 170 | # Microsoft Azure Emulator 171 | ecf/ 172 | rcf/ 173 | 174 | # Windows Store app package directories and files 175 | AppPackages/ 176 | BundleArtifacts/ 177 | Package.StoreAssociation.xml 178 | _pkginfo.txt 179 | 180 | # Visual Studio cache files 181 | # files ending in .cache can be ignored 182 | *.[Cc]ache 183 | # but keep track of directories ending in .cache 184 | !*.[Cc]ache/ 185 | 186 | # Others 187 | ClientBin/ 188 | ~$* 189 | *~ 190 | *.dbmdl 191 | *.dbproj.schemaview 192 | *.jfm 193 | *.pfx 194 | *.publishsettings 195 | node_modules/ 196 | orleans.codegen.cs 197 | 198 | # Since there are multiple workflows, uncomment next line to ignore bower_components 199 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 200 | #bower_components/ 201 | 202 | # RIA/Silverlight projects 203 | Generated_Code/ 204 | 205 | # Backup & report files from converting an old project file 206 | # to a newer Visual Studio version. Backup files are not needed, 207 | # because we have git ;-) 208 | _UpgradeReport_Files/ 209 | Backup*/ 210 | UpgradeLog*.XML 211 | UpgradeLog*.htm 212 | 213 | # SQL Server files 214 | *.mdf 215 | *.ldf 216 | 217 | # Business Intelligence projects 218 | *.rdl.data 219 | *.bim.layout 220 | *.bim_*.settings 221 | 222 | # Microsoft Fakes 223 | FakesAssemblies/ 224 | 225 | # GhostDoc plugin setting file 226 | *.GhostDoc.xml 227 | 228 | # Node.js Tools for Visual Studio 229 | .ntvs_analysis.dat 230 | 231 | # Visual Studio 6 build log 232 | *.plg 233 | 234 | # Visual Studio 6 workspace options file 235 | *.opt 236 | 237 | # Visual Studio LightSwitch build output 238 | **/*.HTMLClient/GeneratedArtifacts 239 | **/*.DesktopClient/GeneratedArtifacts 240 | **/*.DesktopClient/ModelManifest.xml 241 | **/*.Server/GeneratedArtifacts 242 | **/*.Server/ModelManifest.xml 243 | _Pvt_Extensions 244 | 245 | # Paket dependency manager 246 | .paket/paket.exe 247 | paket-files/ 248 | 249 | # FAKE - F# Make 250 | .fake/ 251 | 252 | # JetBrains Rider 253 | .idea/ 254 | *.sln.iml 255 | 256 | # CodeRush 257 | .cr/ 258 | 259 | # Python Tools for Visual Studio (PTVS) 260 | __pycache__/ 261 | *.pyc -------------------------------------------------------------------------------- /11-app-attributes/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": ".NET Core Attach", 6 | "type": "coreclr", 7 | "request": "attach", 8 | "preLaunchTask": "run", 9 | "processId": "${command:pickProcess}" 10 | } 11 | ] 12 | } -------------------------------------------------------------------------------- /11-app-attributes/.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=733558 3 | // for the documentation about the tasks.json format 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "taskName": "build", 8 | "command": "dotnet build", 9 | "type": "shell", 10 | "group": { 11 | "kind": "build", 12 | "isDefault": true 13 | }, 14 | "presentation": { 15 | "reveal": "silent" 16 | }, 17 | "problemMatcher": "$msCompile" 18 | }, 19 | { 20 | "taskName": "publish", 21 | "command": "dotnet publish", 22 | "dependsOn": "build", 23 | "type": "shell", 24 | "problemMatcher": [] 25 | }, 26 | { 27 | "taskName": "run", 28 | "command": "func start --script-root bin\\debug\\netstandard2.0\\publish", 29 | "dependsOn": "publish", 30 | "type": "shell", 31 | "problemMatcher": [] 32 | } 33 | ] 34 | } -------------------------------------------------------------------------------- /11-app-attributes/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Donna Malayeri 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /11-app-attributes/Poll.fs: -------------------------------------------------------------------------------- 1 | namespace PollApp 2 | 3 | open System 4 | open Microsoft.AspNetCore.Mvc 5 | open Microsoft.AspNetCore.Http 6 | open Microsoft.Azure.WebJobs 7 | open Microsoft.Azure.WebJobs.Host 8 | open Microsoft.WindowsAzure.Storage.Table 9 | open Microsoft.Azure.WebJobs.Extensions.Http 10 | 11 | module Utils = 12 | let toOption (n : Nullable<_>) = 13 | if n.HasValue 14 | then Some n.Value 15 | else None 16 | 17 | module Twitter = 18 | 19 | [] 20 | let run([] tweet: string, [] pollResults: ICollector, log: TraceWriter) = 21 | log.Info (sprintf "Tweet: %s" tweet) 22 | pollResults.Add tweet 23 | 24 | 25 | module Landing = 26 | 27 | [] 28 | let run([] req: HttpRequest, []html: string, log: TraceWriter) = 29 | log.Info("F# HTTP trigger function processed a request." + html) 30 | 31 | ContentResult(Content = html, ContentType = "text/html") 32 | 33 | [] 34 | type PollResult = { 35 | value: string 36 | } 37 | 38 | type SentimentResult() = 39 | inherit TableEntity() 40 | member val Text = "" with get, set 41 | member val Score = Nullable() with get, set 42 | 43 | module Send = 44 | 45 | [] 46 | let run([] req: PollResult, [] pollResults: ICollector, log: TraceWriter) = 47 | log.Info (sprintf "Poll result: %s" req.value) 48 | pollResults.Add req.value 49 | 50 | module Sentiment = 51 | open Microsoft.Azure.CognitiveServices.Language.TextAnalytics 52 | open Microsoft.Azure.CognitiveServices.Language.TextAnalytics.Models 53 | 54 | [] 55 | let run ([] feedbackText, log: TraceWriter): [] SentimentResult = 56 | let client = new TextAnalyticsAPI() 57 | client.AzureRegion <- AzureRegions.Westeurope 58 | client.SubscriptionKey <- "65ff5b18c51c4a2ebd4505cbd5fe1e4b" 59 | 60 | let result = client.Sentiment( 61 | MultiLanguageBatchInput( 62 | [| MultiLanguageInput("en", "0", feedbackText) |])) 63 | 64 | let score = 65 | result.Documents 66 | |> Seq.tryHead 67 | |> Option.map (fun x -> x.Score) 68 | |> Option.bind Utils.toOption 69 | 70 | let msg = 71 | match score with 72 | | Some s -> sprintf "Sentiment of %s is %f" feedbackText s 73 | | None -> sprintf "No sentiment for %s" feedbackText 74 | log.Info msg 75 | 76 | let savedScore = 77 | match score with 78 | | Some s -> Nullable(s) 79 | | None -> Nullable() 80 | 81 | SentimentResult(PartitionKey = "default", RowKey = Guid.NewGuid().ToString(), Text = feedbackText, Score = savedScore) 82 | 83 | module Results = 84 | open System.Linq 85 | open Utils 86 | 87 | type Report = { 88 | AverageScore: double 89 | Messages: string list 90 | } 91 | 92 | [] 93 | let run([] req: HttpRequest, []resultsTable: CloudTable, log: TraceWriter) = 94 | 95 | let sentiments = resultsTable.ExecuteQuerySegmentedAsync(new TableQuery(), null).Result.AsEnumerable() 96 | let averageScore = 97 | sentiments 98 | |> Seq.map (fun r -> r.Score) 99 | |> Seq.choose toOption 100 | |> Seq.average 101 | let messages = sentiments |> Seq.map (fun r -> r.Text) |> List.ofSeq 102 | 103 | log.Info(sprintf "Average score: %f" averageScore) 104 | 105 | ObjectResult({ AverageScore = averageScore; Messages = messages }) 106 | 107 | -------------------------------------------------------------------------------- /11-app-attributes/PollApp.fsproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard2.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | PreserveNewest 20 | 21 | 22 | PreserveNewest 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /11-app-attributes/host.json: -------------------------------------------------------------------------------- 1 | { 2 | } -------------------------------------------------------------------------------- /11-app-attributes/local.settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "IsEncrypted": false, 3 | "Values": { 4 | "AzureWebJobsStorage": "UseDevelopmentStorage=true" 5 | } 6 | } -------------------------------------------------------------------------------- /12-durable/.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /12-durable/.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | bld/ 21 | [Bb]in/ 22 | [Oo]bj/ 23 | [Ll]og/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | project.fragment.lock.json 46 | artifacts/ 47 | 48 | *_i.c 49 | *_p.c 50 | *_i.h 51 | *.ilk 52 | *.meta 53 | *.obj 54 | *.pch 55 | *.pdb 56 | *.pgc 57 | *.pgd 58 | *.rsp 59 | *.sbr 60 | *.tlb 61 | *.tli 62 | *.tlh 63 | *.tmp 64 | *.tmp_proj 65 | *.log 66 | *.vspscc 67 | *.vssscc 68 | .builds 69 | *.pidb 70 | *.svclog 71 | *.scc 72 | 73 | # Chutzpah Test files 74 | _Chutzpah* 75 | 76 | # Visual C++ cache files 77 | ipch/ 78 | *.aps 79 | *.ncb 80 | *.opendb 81 | *.opensdf 82 | *.sdf 83 | *.cachefile 84 | *.VC.db 85 | *.VC.VC.opendb 86 | 87 | # Visual Studio profiler 88 | *.psess 89 | *.vsp 90 | *.vspx 91 | *.sap 92 | 93 | # TFS 2012 Local Workspace 94 | $tf/ 95 | 96 | # Guidance Automation Toolkit 97 | *.gpState 98 | 99 | # ReSharper is a .NET coding add-in 100 | _ReSharper*/ 101 | *.[Rr]e[Ss]harper 102 | *.DotSettings.user 103 | 104 | # JustCode is a .NET coding add-in 105 | .JustCode 106 | 107 | # TeamCity is a build add-in 108 | _TeamCity* 109 | 110 | # DotCover is a Code Coverage Tool 111 | *.dotCover 112 | 113 | # NCrunch 114 | _NCrunch_* 115 | .*crunch*.local.xml 116 | nCrunchTemp_* 117 | 118 | # MightyMoose 119 | *.mm.* 120 | AutoTest.Net/ 121 | 122 | # Web workbench (sass) 123 | .sass-cache/ 124 | 125 | # Installshield output folder 126 | [Ee]xpress/ 127 | 128 | # DocProject is a documentation generator add-in 129 | DocProject/buildhelp/ 130 | DocProject/Help/*.HxT 131 | DocProject/Help/*.HxC 132 | DocProject/Help/*.hhc 133 | DocProject/Help/*.hhk 134 | DocProject/Help/*.hhp 135 | DocProject/Help/Html2 136 | DocProject/Help/html 137 | 138 | # Click-Once directory 139 | publish/ 140 | 141 | # Publish Web Output 142 | *.[Pp]ublish.xml 143 | *.azurePubxml 144 | # TODO: Comment the next line if you want to checkin your web deploy settings 145 | # but database connection strings (with potential passwords) will be unencrypted 146 | #*.pubxml 147 | *.publishproj 148 | 149 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 150 | # checkin your Azure Web App publish settings, but sensitive information contained 151 | # in these scripts will be unencrypted 152 | PublishScripts/ 153 | 154 | # NuGet Packages 155 | *.nupkg 156 | # The packages folder can be ignored because of Package Restore 157 | **/packages/* 158 | # except build/, which is used as an MSBuild target. 159 | !**/packages/build/ 160 | # Uncomment if necessary however generally it will be regenerated when needed 161 | #!**/packages/repositories.config 162 | # NuGet v3's project.json files produces more ignoreable files 163 | *.nuget.props 164 | *.nuget.targets 165 | 166 | # Microsoft Azure Build Output 167 | csx/ 168 | *.build.csdef 169 | 170 | # Microsoft Azure Emulator 171 | ecf/ 172 | rcf/ 173 | 174 | # Windows Store app package directories and files 175 | AppPackages/ 176 | BundleArtifacts/ 177 | Package.StoreAssociation.xml 178 | _pkginfo.txt 179 | 180 | # Visual Studio cache files 181 | # files ending in .cache can be ignored 182 | *.[Cc]ache 183 | # but keep track of directories ending in .cache 184 | !*.[Cc]ache/ 185 | 186 | # Others 187 | ClientBin/ 188 | ~$* 189 | *~ 190 | *.dbmdl 191 | *.dbproj.schemaview 192 | *.jfm 193 | *.pfx 194 | *.publishsettings 195 | node_modules/ 196 | orleans.codegen.cs 197 | 198 | # Since there are multiple workflows, uncomment next line to ignore bower_components 199 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 200 | #bower_components/ 201 | 202 | # RIA/Silverlight projects 203 | Generated_Code/ 204 | 205 | # Backup & report files from converting an old project file 206 | # to a newer Visual Studio version. Backup files are not needed, 207 | # because we have git ;-) 208 | _UpgradeReport_Files/ 209 | Backup*/ 210 | UpgradeLog*.XML 211 | UpgradeLog*.htm 212 | 213 | # SQL Server files 214 | *.mdf 215 | *.ldf 216 | 217 | # Business Intelligence projects 218 | *.rdl.data 219 | *.bim.layout 220 | *.bim_*.settings 221 | 222 | # Microsoft Fakes 223 | FakesAssemblies/ 224 | 225 | # GhostDoc plugin setting file 226 | *.GhostDoc.xml 227 | 228 | # Node.js Tools for Visual Studio 229 | .ntvs_analysis.dat 230 | 231 | # Visual Studio 6 build log 232 | *.plg 233 | 234 | # Visual Studio 6 workspace options file 235 | *.opt 236 | 237 | # Visual Studio LightSwitch build output 238 | **/*.HTMLClient/GeneratedArtifacts 239 | **/*.DesktopClient/GeneratedArtifacts 240 | **/*.DesktopClient/ModelManifest.xml 241 | **/*.Server/GeneratedArtifacts 242 | **/*.Server/ModelManifest.xml 243 | _Pvt_Extensions 244 | 245 | # Paket dependency manager 246 | .paket/paket.exe 247 | paket-files/ 248 | 249 | # FAKE - F# Make 250 | .fake/ 251 | 252 | # JetBrains Rider 253 | .idea/ 254 | *.sln.iml 255 | 256 | # CodeRush 257 | .cr/ 258 | 259 | # Python Tools for Visual Studio (PTVS) 260 | __pycache__/ 261 | *.pyc -------------------------------------------------------------------------------- /12-durable/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": ".NET Core Attach", 6 | "type": "coreclr", 7 | "request": "attach", 8 | "preLaunchTask": "run", 9 | "processId": "${command:pickProcess}" 10 | } 11 | ] 12 | } -------------------------------------------------------------------------------- /12-durable/.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=733558 3 | // for the documentation about the tasks.json format 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "taskName": "build", 8 | "command": "dotnet build", 9 | "type": "shell", 10 | "group": { 11 | "kind": "build", 12 | "isDefault": true 13 | }, 14 | "presentation": { 15 | "reveal": "silent" 16 | }, 17 | "problemMatcher": "$msCompile" 18 | }, 19 | { 20 | "taskName": "publish", 21 | "command": "dotnet publish", 22 | "dependsOn": "build", 23 | "type": "shell", 24 | "problemMatcher": [] 25 | }, 26 | { 27 | "taskName": "run", 28 | "command": "func start --script-root bin\\debug\\netstandard2.0\\publish", 29 | "dependsOn": "publish", 30 | "type": "shell", 31 | "problemMatcher": [] 32 | } 33 | ] 34 | } -------------------------------------------------------------------------------- /12-durable/BackupSiteContent.fs: -------------------------------------------------------------------------------- 1 | namespace DurableFsharp 2 | 3 | open System 4 | open System.IO 5 | open System.Threading.Tasks 6 | open Microsoft.Azure.WebJobs 7 | open Microsoft.Azure.WebJobs.Host 8 | open Microsoft.WindowsAzure.Storage.Blob 9 | open FSharp.Control.Tasks 10 | 11 | module BackupSiteContent = 12 | 13 | [] 14 | let Run([] backupContext: DurableOrchestrationContext) = task { 15 | let input = backupContext.GetInput() 16 | let rootDirectory = 17 | if String.IsNullOrEmpty(input) then input.Trim() 18 | else Directory.GetParent(System.Reflection.Assembly.GetExecutingAssembly().Location).FullName 19 | 20 | let! files = backupContext.CallActivityAsync("E2_GetFileList", rootDirectory) 21 | let tasks = Array.map (fun f -> backupContext.CallActivityAsync("E2_CopyFileToBlob", f)) files 22 | let! results = Task.WhenAll tasks 23 | 24 | let totalBytes = Array.sum results 25 | return totalBytes 26 | } 27 | 28 | [] 29 | let GetFileList([] rootDirectory: string, log: TraceWriter) = 30 | log.Info (sprintf "Searching for files under '%s'..." rootDirectory) 31 | let files = Directory.GetFiles(rootDirectory, "*", SearchOption.AllDirectories) 32 | log.Info (sprintf "Found %i file(s) under %s." files.Length rootDirectory) 33 | files 34 | 35 | [] 36 | let CopyFileToBlob([] filePath: string, binder: Binder, log: TraceWriter) = task { 37 | let byteCount = FileInfo(filePath).Length 38 | 39 | // strip the drive letter prefix and convert to forward slashes 40 | let blobPath = filePath.Substring(Path.GetPathRoot(filePath).Length).Replace('\\', '/') 41 | let outputLocation = "backups/" + blobPath 42 | 43 | log.Info (sprintf "Copying '%s' to '%s'. Total bytes = %i." filePath outputLocation byteCount) 44 | 45 | // copy the file contents into a blob 46 | use source = File.Open(filePath, FileMode.Open, FileAccess.Read, FileShare.Read) 47 | let attribute = BlobAttribute(outputLocation, FileAccess.Write) 48 | use! destination = binder.BindAsync attribute 49 | do! source.CopyToAsync destination 50 | 51 | return byteCount 52 | } -------------------------------------------------------------------------------- /12-durable/Counter.fs: -------------------------------------------------------------------------------- 1 | namespace DurableFsharp 2 | 3 | open Microsoft.Azure.WebJobs 4 | open FSharp.Control.Tasks 5 | open Microsoft.Azure.WebJobs.Host 6 | 7 | module Counter = 8 | 9 | [] 10 | let Run([] counterContext: DurableOrchestrationContext, log: TraceWriter) = task { 11 | let counterState = counterContext.GetInput() 12 | log.Info(sprintf "Current counter state is %i. Waiting for next operation." counterState) 13 | 14 | let! command = counterContext.WaitForExternalEvent("operation") 15 | let operation = if isNull command then command else command.ToLowerInvariant() 16 | log.Info(sprintf "Received '%s' operation." operation) 17 | 18 | let newCounter = 19 | match operation with 20 | | "incr" -> counterState + 1 21 | | "decr" -> counterState - 1 22 | | _ -> counterState 23 | 24 | if (operation <> "end") then counterContext.ContinueAsNew(newCounter) 25 | return newCounter 26 | } 27 | 28 | -------------------------------------------------------------------------------- /12-durable/DurableFSharp.fsproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard2.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | PreserveNewest 25 | 26 | 27 | PreserveNewest 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /12-durable/HelloSequence.fs: -------------------------------------------------------------------------------- 1 | namespace DurableFsharp 2 | 3 | open Microsoft.Azure.WebJobs 4 | open FSharp.Control.Tasks 5 | 6 | module HelloSequence = 7 | 8 | [] 9 | let Run([] context: DurableOrchestrationContext) = task { 10 | let! hello1 = context.CallActivityAsync("E1_SayHello", "Tokyo") 11 | let! hello2 = context.CallActivityAsync("E1_SayHello", "Seattle") 12 | let! hello3 = context.CallActivityAsync("E1_SayHello", "London") 13 | return [hello1; hello2; hello3] 14 | } 15 | 16 | [] 17 | let SayHello([] name) = 18 | sprintf "Hello %s!" name 19 | 20 | -------------------------------------------------------------------------------- /12-durable/HttpStart.fs: -------------------------------------------------------------------------------- 1 | namespace DurableFsharp 2 | 3 | open System 4 | open System.Net.Http 5 | open System.Net.Http.Headers 6 | open Microsoft.Azure.WebJobs 7 | open Microsoft.Azure.WebJobs.Host 8 | open Microsoft.Azure.WebJobs.Extensions.Http 9 | 10 | module HttpStart = 11 | 12 | [] 13 | let Run([] req: HttpRequestMessage, 14 | [] starter: DurableOrchestrationClient, 15 | functionName: string, 16 | log: TraceWriter) = 17 | async { 18 | let! eventData = req.Content.ReadAsAsync() |> Async.AwaitTask 19 | let! instanceId = starter.StartNewAsync(functionName, eventData) |> Async.AwaitTask 20 | 21 | log.Info(sprintf "Started orchestration with ID = '{%s}'." instanceId) 22 | 23 | let res = starter.CreateCheckStatusResponse(req, instanceId) 24 | res.Headers.RetryAfter <- RetryConditionHeaderValue(TimeSpan.FromSeconds(10.0)) 25 | return res 26 | } |> Async.StartAsTask -------------------------------------------------------------------------------- /12-durable/HttpSyncStart.fs: -------------------------------------------------------------------------------- 1 | namespace DurableFsharp 2 | 3 | open System 4 | open System.Net.Http 5 | //open System.Net.Http.Headers 6 | open Microsoft.Azure.WebJobs 7 | open Microsoft.Azure.WebJobs.Extensions.Http 8 | open Microsoft.Azure.WebJobs.Host 9 | open FSharp.Control.Tasks 10 | 11 | module HttpSyncStart = 12 | 13 | // let Timeout = "timeout" 14 | // let RetryInterval = "retryInterval" 15 | 16 | // let GetTimeSpan(request: HttpRequestMessage, queryParameterName: string): Nullable = 17 | // let queryParameterStringValue = request.GetQueryNameValuePairs() 18 | // // .FirstOrDefault(x => x.Key == queryParameterName) 19 | // // .Value; 20 | // if String.IsNullOrEmpty(queryParameterStringValue) then Nullable() 21 | // else Nullable() 22 | 23 | [] 24 | let Run([] req: HttpRequestMessage, 25 | [] starter: DurableOrchestrationClient, 26 | functionName: string, 27 | log: TraceWriter) = 28 | task { 29 | let! eventData = req.Content.ReadAsAsync() 30 | let! instanceId = starter.StartNewAsync(functionName, eventData) 31 | 32 | log.Info(sprintf "Started orchestration with ID = '{%s}'." instanceId) 33 | 34 | return! starter.WaitForCompletionOrCreateCheckStatusResponseAsync(req, instanceId, Nullable(), Nullable()) 35 | } -------------------------------------------------------------------------------- /12-durable/PhoneVerification.fs: -------------------------------------------------------------------------------- 1 | namespace DurableFsharp 2 | 3 | open System 4 | open System.Threading 5 | open System.Threading.Tasks 6 | open Microsoft.Azure.WebJobs 7 | open Microsoft.Azure.WebJobs.Host 8 | open Twilio.Rest.Api.V2010.Account 9 | open Twilio.Types 10 | open FSharp.Control.Tasks 11 | 12 | module PhoneVerification = 13 | 14 | [] 15 | let Run([] context: DurableOrchestrationContext) = task { 16 | let phoneNumber = context.GetInput() 17 | if String.IsNullOrEmpty(phoneNumber) 18 | then raise (ArgumentNullException("phoneNumber", "A phone number input is required.")) 19 | 20 | let! challengeCode = context.CallActivityAsync("E4_SendSmsChallenge", phoneNumber) 21 | use timeoutCts = new CancellationTokenSource() 22 | 23 | // The user has 90 seconds to respond with the code they received in the SMS message. 24 | let expiration = context.CurrentUtcDateTime.AddSeconds 90. 25 | let timeoutTask = context.CreateTimer(expiration, timeoutCts.Token) 26 | 27 | let rec challenge i = task { 28 | let challengeResponseTask = context.WaitForExternalEvent("SmsChallengeResponse") 29 | let! winner = Task.WhenAny(challengeResponseTask, timeoutTask) 30 | if (winner = timeoutTask) then return false 31 | elif (challengeResponseTask.Result = challengeCode) then return true 32 | elif i >= 0 then return! challenge (i - 1) 33 | else return false 34 | } 35 | 36 | let! authorized = challenge 3 37 | 38 | // All pending timers must be complete or canceled before the function exits. 39 | if (not timeoutTask.IsCompleted) then timeoutCts.Cancel() 40 | 41 | return authorized 42 | } 43 | 44 | [] 45 | let SendSmsChallenge 46 | ([] phoneNumber: string, 47 | log: TraceWriter, 48 | [] messageCollector: ICollector 49 | ) = 50 | // Get a random number generator with a random seed (not time-based) 51 | let rand = Random(Guid.NewGuid().GetHashCode()) 52 | let challengeCode = rand.Next(10000) 53 | 54 | log.Info (sprintf "Sending verification code %i to %s." challengeCode phoneNumber) 55 | let message = CreateMessageOptions(PhoneNumber(phoneNumber)) 56 | message.Body <- sprintf "Your verification code is %i:0000" challengeCode 57 | messageCollector.Add message 58 | 59 | challengeCode -------------------------------------------------------------------------------- /12-durable/host.json: -------------------------------------------------------------------------------- 1 | { 2 | } -------------------------------------------------------------------------------- /12-durable/local.settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "IsEncrypted": false, 3 | "Values": { 4 | "AzureWebJobsStorage": "UseDevelopmentStorage=true", 5 | "TwilioAccountSid": "", 6 | "TwilioAuthToken": "", 7 | "TwilioPhoneNumber": "" 8 | } 9 | } -------------------------------------------------------------------------------- /13-fsharp-from-csharp/CSharpFunctionApp/CSharpFunctionApp.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | netstandard2.0 4 | v2 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | PreserveNewest 15 | 16 | 17 | PreserveNewest 18 | Never 19 | 20 | 21 | -------------------------------------------------------------------------------- /13-fsharp-from-csharp/CSharpFunctionApp/CSharpFunctions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Mvc; 2 | using Microsoft.Azure.WebJobs; 3 | using Microsoft.Azure.WebJobs.Extensions.Http; 4 | using Microsoft.AspNetCore.Http; 5 | using Microsoft.Azure.WebJobs.Host; 6 | 7 | namespace CSharpFunctionApp 8 | { 9 | public static class CSharpFunctions 10 | { 11 | [FunctionName("CSharpLovesFSharp")] 12 | public static IActionResult Run([HttpTrigger(AuthorizationLevel.Function, "get")]HttpRequest req, TraceWriter log) 13 | { 14 | var greeting = FSharpLibrary.Say.loves("C#", "F#"); 15 | 16 | log.Info(greeting); 17 | 18 | return new OkObjectResult(greeting); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /13-fsharp-from-csharp/CSharpFunctionApp/host.json: -------------------------------------------------------------------------------- 1 | { 2 | } -------------------------------------------------------------------------------- /13-fsharp-from-csharp/CSharpFunctionApp/local.settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "IsEncrypted": false, 3 | "Values": { 4 | "AzureWebJobsStorage": "UseDevelopmentStorage=true" 5 | } 6 | } -------------------------------------------------------------------------------- /13-fsharp-from-csharp/FSharpLibrary/FSharpLibrary.fsproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard2.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /13-fsharp-from-csharp/FSharpLibrary/Library.fs: -------------------------------------------------------------------------------- 1 | namespace FSharpLibrary 2 | 3 | module Say = 4 | let loves who whom = 5 | sprintf "%s loves %s" who whom 6 | -------------------------------------------------------------------------------- /13-fsharp-from-csharp/FsharpFromCsharpFunction.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.27703.2018 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CSharpFunctionApp", "CSharpFunctionApp\CSharpFunctionApp.csproj", "{5CFED223-075F-4EC6-947A-AB1A79250333}" 7 | EndProject 8 | Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "FSharpLibrary", "FSharpLibrary\FSharpLibrary.fsproj", "{3487EBB0-20AF-4E1D-AD81-7474304B9572}" 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 | {5CFED223-075F-4EC6-947A-AB1A79250333}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 17 | {5CFED223-075F-4EC6-947A-AB1A79250333}.Debug|Any CPU.Build.0 = Debug|Any CPU 18 | {5CFED223-075F-4EC6-947A-AB1A79250333}.Release|Any CPU.ActiveCfg = Release|Any CPU 19 | {5CFED223-075F-4EC6-947A-AB1A79250333}.Release|Any CPU.Build.0 = Release|Any CPU 20 | {3487EBB0-20AF-4E1D-AD81-7474304B9572}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {3487EBB0-20AF-4E1D-AD81-7474304B9572}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {3487EBB0-20AF-4E1D-AD81-7474304B9572}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {3487EBB0-20AF-4E1D-AD81-7474304B9572}.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 = {542087B7-F632-48A9-86B1-99D5DA1BB16A} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /2-portal-http/function.json: -------------------------------------------------------------------------------- 1 | { 2 | "bindings": [ 3 | { 4 | "authLevel": "function", 5 | "name": "req", 6 | "type": "httpTrigger", 7 | "direction": "in" 8 | }, 9 | { 10 | "name": "res", 11 | "type": "http", 12 | "direction": "out" 13 | } 14 | ], 15 | "disabled": false 16 | } -------------------------------------------------------------------------------- /2-portal-http/run.fsx: -------------------------------------------------------------------------------- 1 | open System.Net 2 | 3 | type Named = { 4 | name: string 5 | } 6 | 7 | let run (req: Named) (log: TraceWriter) = 8 | log.Info (sprintf "Got a request from %s" req.name) 9 | 10 | let responseMessage = new HttpResponseMessage(HttpStatusCode.OK) 11 | responseMessage.Content <- new StringContent("Hello " + req.name) 12 | responseMessage -------------------------------------------------------------------------------- /3-portal-http-html/function.json: -------------------------------------------------------------------------------- 1 | { 2 | "bindings": [ 3 | { 4 | "authLevel": "anonymous", 5 | "name": "req", 6 | "type": "httpTrigger", 7 | "direction": "in", 8 | "route": "{filename}/{name}" 9 | }, 10 | { 11 | "name": "res", 12 | "type": "http", 13 | "direction": "out" 14 | }, 15 | { 16 | "type": "blob", 17 | "name": "template", 18 | "path": "html/{filename}.html", 19 | "direction": "in" 20 | } 21 | ], 22 | "disabled": false 23 | } -------------------------------------------------------------------------------- /3-portal-http-html/html/awesome.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |

%name%!

4 |

You

5 |

are

6 |

AWESOME!

7 | 8 | -------------------------------------------------------------------------------- /3-portal-http-html/html/hello.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |

Hello %name%

4 | 5 | -------------------------------------------------------------------------------- /3-portal-http-html/run.fsx: -------------------------------------------------------------------------------- 1 | open System.Text 2 | open System.Net 3 | open System.Net.Http 4 | 5 | let Run(req: HttpRequestMessage, template: string, name: string) = 6 | let html = template.Replace("%name%", name) 7 | 8 | let response = req.CreateResponse(HttpStatusCode.OK) 9 | response.Content <- new StringContent(html, Encoding.UTF8, "text/html") 10 | response -------------------------------------------------------------------------------- /4-cli-http/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | bin 3 | obj 4 | csx 5 | .vs 6 | edge 7 | Publish 8 | .vscode 9 | 10 | *.user 11 | *.suo 12 | *.cscfg 13 | *.Cache 14 | project.lock.json 15 | 16 | /packages 17 | /TestResults 18 | 19 | /tools/NuGet.exe 20 | /App_Data 21 | /secrets 22 | /data 23 | .secrets 24 | appsettings.json 25 | local.settings.json 26 | -------------------------------------------------------------------------------- /4-cli-http/cli-http/function.json: -------------------------------------------------------------------------------- 1 | { 2 | "disabled": false, 3 | "bindings": [ 4 | { 5 | "authLevel": "function", 6 | "name": "req", 7 | "type": "httpTrigger", 8 | "direction": "in" 9 | }, 10 | { 11 | "name": "res", 12 | "type": "http", 13 | "direction": "out" 14 | } 15 | ] 16 | } -------------------------------------------------------------------------------- /4-cli-http/cli-http/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "frameworks": { 3 | "net46":{ 4 | "dependencies": { 5 | "FSharp.Interop.Dynamic": "3.0.0" 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /4-cli-http/cli-http/run.fsx: -------------------------------------------------------------------------------- 1 | #if INTERACTIVE 2 | 3 | open System 4 | 5 | #I @"C:/Users/username/AppData/Roaming/npm/node_modules/azure-functions-core-tools/bin/" 6 | 7 | #r "Microsoft.Azure.Webjobs.Host.dll" 8 | open Microsoft.Azure.WebJobs.Host 9 | 10 | #r "System.Net.Http.Formatting.dll" 11 | #r "System.Web.Http.dll" 12 | #r "System.Net.Http.dll" 13 | #r "Newtonsoft.Json.dll" 14 | 15 | #else 16 | 17 | #r "System.Net.Http" 18 | #r "Newtonsoft.Json" 19 | 20 | #endif 21 | 22 | open System.Net 23 | open System.Net.Http 24 | open Newtonsoft.Json 25 | 26 | type Named = { 27 | name: string 28 | } 29 | 30 | let Run(req: HttpRequestMessage, log: TraceWriter) = 31 | async { 32 | log.Info(sprintf 33 | "F# HTTP trigger function processed a request.") 34 | 35 | // Set name to query string 36 | let name = 37 | req.GetQueryNameValuePairs() 38 | |> Seq.tryFind (fun q -> q.Key = "name") 39 | 40 | match name with 41 | | Some x -> 42 | return req.CreateResponse(HttpStatusCode.OK, "Hello " + x.Value); 43 | | None -> 44 | let! data = req.Content.ReadAsStringAsync() |> Async.AwaitTask 45 | 46 | if not (String.IsNullOrEmpty(data)) then 47 | let named = JsonConvert.DeserializeObject(data) 48 | return req.CreateResponse(HttpStatusCode.OK, "Hello " + named.name); 49 | else 50 | return req.CreateResponse(HttpStatusCode.BadRequest, "Specify a Name value"); 51 | } |> Async.RunSynchronously 52 | -------------------------------------------------------------------------------- /4-cli-http/cli-http/sample.dat: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Azure" 3 | } -------------------------------------------------------------------------------- /4-cli-http/host.json: -------------------------------------------------------------------------------- 1 | { } -------------------------------------------------------------------------------- /5-precompiled-full-framework/.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /5-precompiled-full-framework/.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | bld/ 21 | [Bb]in/ 22 | [Oo]bj/ 23 | [Ll]og/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | project.fragment.lock.json 46 | artifacts/ 47 | 48 | *_i.c 49 | *_p.c 50 | *_i.h 51 | *.ilk 52 | *.meta 53 | *.obj 54 | *.pch 55 | *.pdb 56 | *.pgc 57 | *.pgd 58 | *.rsp 59 | *.sbr 60 | *.tlb 61 | *.tli 62 | *.tlh 63 | *.tmp 64 | *.tmp_proj 65 | *.log 66 | *.vspscc 67 | *.vssscc 68 | .builds 69 | *.pidb 70 | *.svclog 71 | *.scc 72 | 73 | # Chutzpah Test files 74 | _Chutzpah* 75 | 76 | # Visual C++ cache files 77 | ipch/ 78 | *.aps 79 | *.ncb 80 | *.opendb 81 | *.opensdf 82 | *.sdf 83 | *.cachefile 84 | *.VC.db 85 | *.VC.VC.opendb 86 | 87 | # Visual Studio profiler 88 | *.psess 89 | *.vsp 90 | *.vspx 91 | *.sap 92 | 93 | # TFS 2012 Local Workspace 94 | $tf/ 95 | 96 | # Guidance Automation Toolkit 97 | *.gpState 98 | 99 | # ReSharper is a .NET coding add-in 100 | _ReSharper*/ 101 | *.[Rr]e[Ss]harper 102 | *.DotSettings.user 103 | 104 | # JustCode is a .NET coding add-in 105 | .JustCode 106 | 107 | # TeamCity is a build add-in 108 | _TeamCity* 109 | 110 | # DotCover is a Code Coverage Tool 111 | *.dotCover 112 | 113 | # NCrunch 114 | _NCrunch_* 115 | .*crunch*.local.xml 116 | nCrunchTemp_* 117 | 118 | # MightyMoose 119 | *.mm.* 120 | AutoTest.Net/ 121 | 122 | # Web workbench (sass) 123 | .sass-cache/ 124 | 125 | # Installshield output folder 126 | [Ee]xpress/ 127 | 128 | # DocProject is a documentation generator add-in 129 | DocProject/buildhelp/ 130 | DocProject/Help/*.HxT 131 | DocProject/Help/*.HxC 132 | DocProject/Help/*.hhc 133 | DocProject/Help/*.hhk 134 | DocProject/Help/*.hhp 135 | DocProject/Help/Html2 136 | DocProject/Help/html 137 | 138 | # Click-Once directory 139 | publish/ 140 | 141 | # Publish Web Output 142 | *.[Pp]ublish.xml 143 | *.azurePubxml 144 | # TODO: Comment the next line if you want to checkin your web deploy settings 145 | # but database connection strings (with potential passwords) will be unencrypted 146 | #*.pubxml 147 | *.publishproj 148 | 149 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 150 | # checkin your Azure Web App publish settings, but sensitive information contained 151 | # in these scripts will be unencrypted 152 | PublishScripts/ 153 | 154 | # NuGet Packages 155 | *.nupkg 156 | # The packages folder can be ignored because of Package Restore 157 | **/packages/* 158 | # except build/, which is used as an MSBuild target. 159 | !**/packages/build/ 160 | # Uncomment if necessary however generally it will be regenerated when needed 161 | #!**/packages/repositories.config 162 | # NuGet v3's project.json files produces more ignoreable files 163 | *.nuget.props 164 | *.nuget.targets 165 | 166 | # Microsoft Azure Build Output 167 | csx/ 168 | *.build.csdef 169 | 170 | # Microsoft Azure Emulator 171 | ecf/ 172 | rcf/ 173 | 174 | # Windows Store app package directories and files 175 | AppPackages/ 176 | BundleArtifacts/ 177 | Package.StoreAssociation.xml 178 | _pkginfo.txt 179 | 180 | # Visual Studio cache files 181 | # files ending in .cache can be ignored 182 | *.[Cc]ache 183 | # but keep track of directories ending in .cache 184 | !*.[Cc]ache/ 185 | 186 | # Others 187 | ClientBin/ 188 | ~$* 189 | *~ 190 | *.dbmdl 191 | *.dbproj.schemaview 192 | *.jfm 193 | *.pfx 194 | *.publishsettings 195 | node_modules/ 196 | orleans.codegen.cs 197 | 198 | # Since there are multiple workflows, uncomment next line to ignore bower_components 199 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 200 | #bower_components/ 201 | 202 | # RIA/Silverlight projects 203 | Generated_Code/ 204 | 205 | # Backup & report files from converting an old project file 206 | # to a newer Visual Studio version. Backup files are not needed, 207 | # because we have git ;-) 208 | _UpgradeReport_Files/ 209 | Backup*/ 210 | UpgradeLog*.XML 211 | UpgradeLog*.htm 212 | 213 | # SQL Server files 214 | *.mdf 215 | *.ldf 216 | 217 | # Business Intelligence projects 218 | *.rdl.data 219 | *.bim.layout 220 | *.bim_*.settings 221 | 222 | # Microsoft Fakes 223 | FakesAssemblies/ 224 | 225 | # GhostDoc plugin setting file 226 | *.GhostDoc.xml 227 | 228 | # Node.js Tools for Visual Studio 229 | .ntvs_analysis.dat 230 | 231 | # Visual Studio 6 build log 232 | *.plg 233 | 234 | # Visual Studio 6 workspace options file 235 | *.opt 236 | 237 | # Visual Studio LightSwitch build output 238 | **/*.HTMLClient/GeneratedArtifacts 239 | **/*.DesktopClient/GeneratedArtifacts 240 | **/*.DesktopClient/ModelManifest.xml 241 | **/*.Server/GeneratedArtifacts 242 | **/*.Server/ModelManifest.xml 243 | _Pvt_Extensions 244 | 245 | # Paket dependency manager 246 | .paket/paket.exe 247 | paket-files/ 248 | 249 | # FAKE - F# Make 250 | .fake/ 251 | 252 | # JetBrains Rider 253 | .idea/ 254 | *.sln.iml 255 | 256 | # CodeRush 257 | .cr/ 258 | 259 | # Python Tools for Visual Studio (PTVS) 260 | __pycache__/ 261 | *.pyc -------------------------------------------------------------------------------- /5-precompiled-full-framework/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": ".NET Core Attach", 6 | "type": "coreclr", 7 | "request": "attach", 8 | "preLaunchTask": "run", 9 | "processId": "${command:pickProcess}" 10 | } 11 | ] 12 | } -------------------------------------------------------------------------------- /5-precompiled-full-framework/.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=733558 3 | // for the documentation about the tasks.json format 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "taskName": "build", 8 | "command": "dotnet build", 9 | "type": "shell", 10 | "group": { 11 | "kind": "build", 12 | "isDefault": true 13 | }, 14 | "presentation": { 15 | "reveal": "silent" 16 | }, 17 | "problemMatcher": "$msCompile" 18 | }, 19 | { 20 | "taskName": "publish", 21 | "command": "dotnet publish", 22 | "dependsOn": "build", 23 | "type": "shell", 24 | "problemMatcher": [] 25 | }, 26 | { 27 | "taskName": "run", 28 | "command": "cd bin\\debug\\net462\\publish;func host start", 29 | "dependsOn": "publish", 30 | "type": "shell", 31 | "problemMatcher": [] 32 | } 33 | ] 34 | } -------------------------------------------------------------------------------- /5-precompiled-full-framework/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Donna Malayeri 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /5-precompiled-full-framework/PrecompiledApp.fsproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net462 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | PreserveNewest 24 | 25 | 26 | PreserveNewest 27 | 28 | 29 | PreserveNewest 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /5-precompiled-full-framework/PrecompiledHttp/PrecompiledHttp.fs: -------------------------------------------------------------------------------- 1 | namespace PrecompiledApp 2 | 3 | open Microsoft.AspNetCore.Mvc 4 | open Microsoft.AspNetCore.Http 5 | open Microsoft.Azure.WebJobs.Host 6 | 7 | module PrecompiledHttp = 8 | let run(req: HttpRequest, log: TraceWriter) = 9 | log.Info("F# HTTP trigger function processed a request.") 10 | log.Info(System.Configuration.ConfigurationManager.AppSettings.Count |> string) 11 | 12 | ContentResult(Content = "Boom! Precompiled .NET Core function works!", ContentType = "text/html") 13 | -------------------------------------------------------------------------------- /5-precompiled-full-framework/PrecompiledHttp/function.json: -------------------------------------------------------------------------------- 1 | { 2 | "bindings": [ 3 | { 4 | "type": "httpTrigger", 5 | "methods": ["get"], 6 | "authLevel": "anonymous", 7 | "name": "req", 8 | "route": "precompiled" 9 | } 10 | ], 11 | "scriptFile": "../bin/PrecompiledApp.dll", 12 | "entryPoint": "PrecompiledApp.PrecompiledHttp.run" 13 | } -------------------------------------------------------------------------------- /5-precompiled-full-framework/host.json: -------------------------------------------------------------------------------- 1 | { 2 | } -------------------------------------------------------------------------------- /5-precompiled-full-framework/local.settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "IsEncrypted": false, 3 | "Values": { 4 | "AzureWebJobsStorage": "UseDevelopmentStorage=true" 5 | } 6 | } -------------------------------------------------------------------------------- /5-precompiled/.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /5-precompiled/.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | bld/ 21 | [Bb]in/ 22 | [Oo]bj/ 23 | [Ll]og/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | project.fragment.lock.json 46 | artifacts/ 47 | 48 | *_i.c 49 | *_p.c 50 | *_i.h 51 | *.ilk 52 | *.meta 53 | *.obj 54 | *.pch 55 | *.pdb 56 | *.pgc 57 | *.pgd 58 | *.rsp 59 | *.sbr 60 | *.tlb 61 | *.tli 62 | *.tlh 63 | *.tmp 64 | *.tmp_proj 65 | *.log 66 | *.vspscc 67 | *.vssscc 68 | .builds 69 | *.pidb 70 | *.svclog 71 | *.scc 72 | 73 | # Chutzpah Test files 74 | _Chutzpah* 75 | 76 | # Visual C++ cache files 77 | ipch/ 78 | *.aps 79 | *.ncb 80 | *.opendb 81 | *.opensdf 82 | *.sdf 83 | *.cachefile 84 | *.VC.db 85 | *.VC.VC.opendb 86 | 87 | # Visual Studio profiler 88 | *.psess 89 | *.vsp 90 | *.vspx 91 | *.sap 92 | 93 | # TFS 2012 Local Workspace 94 | $tf/ 95 | 96 | # Guidance Automation Toolkit 97 | *.gpState 98 | 99 | # ReSharper is a .NET coding add-in 100 | _ReSharper*/ 101 | *.[Rr]e[Ss]harper 102 | *.DotSettings.user 103 | 104 | # JustCode is a .NET coding add-in 105 | .JustCode 106 | 107 | # TeamCity is a build add-in 108 | _TeamCity* 109 | 110 | # DotCover is a Code Coverage Tool 111 | *.dotCover 112 | 113 | # NCrunch 114 | _NCrunch_* 115 | .*crunch*.local.xml 116 | nCrunchTemp_* 117 | 118 | # MightyMoose 119 | *.mm.* 120 | AutoTest.Net/ 121 | 122 | # Web workbench (sass) 123 | .sass-cache/ 124 | 125 | # Installshield output folder 126 | [Ee]xpress/ 127 | 128 | # DocProject is a documentation generator add-in 129 | DocProject/buildhelp/ 130 | DocProject/Help/*.HxT 131 | DocProject/Help/*.HxC 132 | DocProject/Help/*.hhc 133 | DocProject/Help/*.hhk 134 | DocProject/Help/*.hhp 135 | DocProject/Help/Html2 136 | DocProject/Help/html 137 | 138 | # Click-Once directory 139 | publish/ 140 | 141 | # Publish Web Output 142 | *.[Pp]ublish.xml 143 | *.azurePubxml 144 | # TODO: Comment the next line if you want to checkin your web deploy settings 145 | # but database connection strings (with potential passwords) will be unencrypted 146 | #*.pubxml 147 | *.publishproj 148 | 149 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 150 | # checkin your Azure Web App publish settings, but sensitive information contained 151 | # in these scripts will be unencrypted 152 | PublishScripts/ 153 | 154 | # NuGet Packages 155 | *.nupkg 156 | # The packages folder can be ignored because of Package Restore 157 | **/packages/* 158 | # except build/, which is used as an MSBuild target. 159 | !**/packages/build/ 160 | # Uncomment if necessary however generally it will be regenerated when needed 161 | #!**/packages/repositories.config 162 | # NuGet v3's project.json files produces more ignoreable files 163 | *.nuget.props 164 | *.nuget.targets 165 | 166 | # Microsoft Azure Build Output 167 | csx/ 168 | *.build.csdef 169 | 170 | # Microsoft Azure Emulator 171 | ecf/ 172 | rcf/ 173 | 174 | # Windows Store app package directories and files 175 | AppPackages/ 176 | BundleArtifacts/ 177 | Package.StoreAssociation.xml 178 | _pkginfo.txt 179 | 180 | # Visual Studio cache files 181 | # files ending in .cache can be ignored 182 | *.[Cc]ache 183 | # but keep track of directories ending in .cache 184 | !*.[Cc]ache/ 185 | 186 | # Others 187 | ClientBin/ 188 | ~$* 189 | *~ 190 | *.dbmdl 191 | *.dbproj.schemaview 192 | *.jfm 193 | *.pfx 194 | *.publishsettings 195 | node_modules/ 196 | orleans.codegen.cs 197 | 198 | # Since there are multiple workflows, uncomment next line to ignore bower_components 199 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 200 | #bower_components/ 201 | 202 | # RIA/Silverlight projects 203 | Generated_Code/ 204 | 205 | # Backup & report files from converting an old project file 206 | # to a newer Visual Studio version. Backup files are not needed, 207 | # because we have git ;-) 208 | _UpgradeReport_Files/ 209 | Backup*/ 210 | UpgradeLog*.XML 211 | UpgradeLog*.htm 212 | 213 | # SQL Server files 214 | *.mdf 215 | *.ldf 216 | 217 | # Business Intelligence projects 218 | *.rdl.data 219 | *.bim.layout 220 | *.bim_*.settings 221 | 222 | # Microsoft Fakes 223 | FakesAssemblies/ 224 | 225 | # GhostDoc plugin setting file 226 | *.GhostDoc.xml 227 | 228 | # Node.js Tools for Visual Studio 229 | .ntvs_analysis.dat 230 | 231 | # Visual Studio 6 build log 232 | *.plg 233 | 234 | # Visual Studio 6 workspace options file 235 | *.opt 236 | 237 | # Visual Studio LightSwitch build output 238 | **/*.HTMLClient/GeneratedArtifacts 239 | **/*.DesktopClient/GeneratedArtifacts 240 | **/*.DesktopClient/ModelManifest.xml 241 | **/*.Server/GeneratedArtifacts 242 | **/*.Server/ModelManifest.xml 243 | _Pvt_Extensions 244 | 245 | # Paket dependency manager 246 | .paket/paket.exe 247 | paket-files/ 248 | 249 | # FAKE - F# Make 250 | .fake/ 251 | 252 | # JetBrains Rider 253 | .idea/ 254 | *.sln.iml 255 | 256 | # CodeRush 257 | .cr/ 258 | 259 | # Python Tools for Visual Studio (PTVS) 260 | __pycache__/ 261 | *.pyc -------------------------------------------------------------------------------- /5-precompiled/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": ".NET Core Attach", 6 | "type": "coreclr", 7 | "request": "attach", 8 | "preLaunchTask": "run", 9 | "processId": "${command:pickProcess}" 10 | } 11 | ] 12 | } -------------------------------------------------------------------------------- /5-precompiled/.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=733558 3 | // for the documentation about the tasks.json format 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "taskName": "build", 8 | "command": "dotnet build", 9 | "type": "shell", 10 | "group": { 11 | "kind": "build", 12 | "isDefault": true 13 | }, 14 | "presentation": { 15 | "reveal": "silent" 16 | }, 17 | "problemMatcher": "$msCompile" 18 | }, 19 | { 20 | "taskName": "publish", 21 | "command": "dotnet publish", 22 | "dependsOn": "build", 23 | "type": "shell", 24 | "problemMatcher": [] 25 | }, 26 | { 27 | "taskName": "run", 28 | "command": "func start --script-root bin\\debug\\netstandard2.0\\publish", 29 | "dependsOn": "publish", 30 | "type": "shell", 31 | "problemMatcher": [] 32 | } 33 | ] 34 | } -------------------------------------------------------------------------------- /5-precompiled/PrecompiledApp.fsproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard2.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | PreserveNewest 20 | 21 | 22 | PreserveNewest 23 | 24 | 25 | PreserveNewest 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /5-precompiled/PrecompiledHttp/PrecompiledHttp.fs: -------------------------------------------------------------------------------- 1 | namespace PrecompiledApp 2 | 3 | open Microsoft.AspNetCore.Mvc 4 | open Microsoft.AspNetCore.Http 5 | open Microsoft.Azure.WebJobs.Host 6 | 7 | module PrecompiledHttp = 8 | let run(req: HttpRequest, log: TraceWriter) = 9 | log.Info("F# HTTP trigger function processed a request.") 10 | 11 | ContentResult(Content = "Boom! Precompiled .NET Core function works!", ContentType = "text/html") 12 | -------------------------------------------------------------------------------- /5-precompiled/PrecompiledHttp/function.json: -------------------------------------------------------------------------------- 1 | { 2 | "bindings": [ 3 | { 4 | "type": "httpTrigger", 5 | "methods": ["get"], 6 | "authLevel": "anonymous", 7 | "name": "req", 8 | "route": "hellosanta" 9 | } 10 | ], 11 | "scriptFile": "../bin/PrecompiledApp.dll", 12 | "entryPoint": "PrecompiledApp.PrecompiledHttp.run" 13 | } -------------------------------------------------------------------------------- /5-precompiled/host.json: -------------------------------------------------------------------------------- 1 | { 2 | } -------------------------------------------------------------------------------- /5-precompiled/local.settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "IsEncrypted": false, 3 | "Values": { 4 | "AzureWebJobsStorage": "UseDevelopmentStorage=true" 5 | } 6 | } -------------------------------------------------------------------------------- /6-precompiled-timer/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": ".NET Core Attach", 6 | "type": "coreclr", 7 | "request": "attach", 8 | "preLaunchTask": "run", 9 | "processId": "${command:pickProcess}" 10 | } 11 | ] 12 | } -------------------------------------------------------------------------------- /6-precompiled-timer/.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=733558 3 | // for the documentation about the tasks.json format 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "taskName": "build", 8 | "command": "dotnet build", 9 | "type": "shell", 10 | "group": { 11 | "kind": "build", 12 | "isDefault": true 13 | }, 14 | "presentation": { 15 | "reveal": "silent" 16 | }, 17 | "problemMatcher": "$msCompile" 18 | }, 19 | { 20 | "taskName": "publish", 21 | "command": "dotnet publish", 22 | "dependsOn": "build", 23 | "type": "shell", 24 | "problemMatcher": [] 25 | }, 26 | { 27 | "taskName": "run", 28 | "command": "func start --script-root bin\\debug\\netstandard2.0\\publish", 29 | "dependsOn": "publish", 30 | "type": "shell", 31 | "problemMatcher": [] 32 | } 33 | ] 34 | } -------------------------------------------------------------------------------- /6-precompiled-timer/Hello/function.json: -------------------------------------------------------------------------------- 1 | { 2 | "bindings": [ 3 | { 4 | "name": "timer", 5 | "type": "timerTrigger", 6 | "schedule": "0 * * * * *" 7 | } 8 | ], 9 | "scriptFile": "../bin/HelloFunctions.dll", 10 | "entryPoint": "HelloFunctions.Say.hello" 11 | } -------------------------------------------------------------------------------- /6-precompiled-timer/HelloFunctions.fsproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard2.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | PreserveNewest 18 | 19 | 20 | PreserveNewest 21 | 22 | 23 | PreserveNewest 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /6-precompiled-timer/Library.fs: -------------------------------------------------------------------------------- 1 | namespace HelloFunctions 2 | 3 | open System 4 | open Microsoft.Azure.WebJobs 5 | open Microsoft.Azure.WebJobs.Host 6 | 7 | module Say = 8 | let private daysUntil (d: DateTime) = 9 | (d - DateTime.Now).TotalDays |> int 10 | 11 | let hello (timer: TimerInfo, log: TraceWriter) = 12 | let christmas = new DateTime(2017, 12, 25) 13 | 14 | daysUntil christmas 15 | |> sprintf "%d days until Christmas" 16 | |> log.Info 17 | -------------------------------------------------------------------------------- /6-precompiled-timer/host.json: -------------------------------------------------------------------------------- 1 | { 2 | } -------------------------------------------------------------------------------- /6-precompiled-timer/local.settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "IsEncrypted": false, 3 | "Values": { 4 | "AzureWebJobsStorage": "UseDevelopmentStorage=true" 5 | } 6 | } -------------------------------------------------------------------------------- /6b-precompiled-http-to-service-bus-topic/FromHttpTriggerToServiceBusTopic.fs: -------------------------------------------------------------------------------- 1 | namespace Azure.Messaging.Demo.Server 2 | 3 | open FSharp.Control.Tasks.V2 4 | open Microsoft.AspNetCore.Http 5 | open Microsoft.AspNetCore.Mvc 6 | open Microsoft.Extensions.Logging 7 | open Microsoft.Azure.ServiceBus 8 | open Microsoft.Azure.WebJobs 9 | open Microsoft.Azure.WebJobs.Extensions.Http 10 | open Microsoft.Azure.WebJobs.ServiceBus 11 | open Newtonsoft.Json 12 | open System.IO 13 | open System.Text 14 | 15 | [] 16 | type MyCustomType = { 17 | SessionId: string 18 | EventId: int } 19 | 20 | module FromHttpTriggerToServiceBusTopic = 21 | [] 22 | let MessageContentType = "application/json" 23 | [] 24 | let TopicName = "my-topic-name" 25 | // See usage in the ServiceBus attribute below. 26 | // this will automagically pick up the 'value' of the app setting called 'ServiceBusConnectionString' 27 | [] 28 | let ServiceBusConnectionString = "ServiceBusConnectionString" 29 | 30 | /// Convert the given event to a Service Bus message. 31 | let toMessage payload = 32 | Message( 33 | SessionId = payload.SessionId, 34 | Body = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(payload)), 35 | ContentType = MessageContentType) 36 | 37 | [] 38 | let run 39 | ([] req: HttpRequest) 40 | ([] topic: IAsyncCollector) 41 | (log: ILogger) = task { 42 | use stream = new StreamReader(req.Body) 43 | let! reqBody = stream.ReadToEndAsync() |> Async.AwaitTask 44 | let myCustomData = JsonConvert.DeserializeObject(reqBody) 45 | 46 | // IAsyncCollector.AddAsync might potentially throw and in that case you're on your own (try / catch + retry?). 47 | do! topic.AddAsync(toMessage myCustomData) 48 | return OkObjectResult("Processed.") :> IActionResult } 49 | -------------------------------------------------------------------------------- /6b-precompiled-http-to-service-bus-topic/FromHttpTriggerToServiceBusTopic.fsproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | netcoreapp3.1 4 | v3 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | PreserveNewest 21 | 22 | 23 | Always 24 | Always 25 | 26 | 27 | 28 | 29 | 30 | PreserveNewest 31 | Never 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /6b-precompiled-http-to-service-bus-topic/README.MD: -------------------------------------------------------------------------------- 1 | Sample Azure Function (V3) written in F# that triggers based on a HTTP request and publishes a message to an `Azure Service Bus topic` through [output bindings](https://docs.microsoft.com/en-us/azure/azure-functions/functions-bindings-service-bus-output?tabs=csharp). 2 | The function also uses the [Azure Function Proxies](https://docs.microsoft.com/en-us/azure/azure-functions/functions-proxies) functionality. 3 | See the `proxies.json` file for more details. You can refer to app settings by using the `%MY-APP-SETTING-KEY%` syntax. -------------------------------------------------------------------------------- /6b-precompiled-http-to-service-bus-topic/host.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0", 3 | "logging": { 4 | "applicationInsights": { 5 | "samplingExcludedTypes": "Request", 6 | "samplingSettings": { 7 | "isEnabled": true 8 | } 9 | } 10 | } 11 | } -------------------------------------------------------------------------------- /6b-precompiled-http-to-service-bus-topic/local.settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "IsEncrypted": false, 3 | "Values": { 4 | "AzureWebJobsStorage": "UseDevelopmentStorage=true", 5 | "FUNCTIONS_WORKER_RUNTIME": "dotnet", 6 | "WEB_HOST": "http://localhost:7071", 7 | "ServiceBusConnectionString": "Endpoint=sb://the-rest-of-your-service-bus-connection-string-with-shared-access-key-goes-here" 8 | } 9 | } -------------------------------------------------------------------------------- /6b-precompiled-http-to-service-bus-topic/proxies.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json.schemastore.org/proxies", 3 | "proxies": { 4 | "FromHttpTriggerToServiceBusTopic Proxy": { 5 | "matchCondition": { 6 | "methods": [ "POST" ], 7 | "route": "/my-proxy-url" 8 | }, 9 | "backendUri": "%WEB_HOST%/api/FromHttpTriggerToServiceBusTopic" 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /7-suave/.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.suo 8 | *.user 9 | *.userosscache 10 | *.sln.docstates 11 | 12 | # User-specific files (MonoDevelop/Xamarin Studio) 13 | *.userprefs 14 | 15 | # Build results 16 | [Dd]ebug/ 17 | [Dd]ebugPublic/ 18 | [Rr]elease/ 19 | [Rr]eleases/ 20 | x64/ 21 | x86/ 22 | bld/ 23 | [Bb]in/ 24 | [Oo]bj/ 25 | [Ll]og/ 26 | 27 | # Visual Studio 2015 cache/options directory 28 | .vs/ 29 | # Uncomment if you have tasks that create the project's static files in wwwroot 30 | #wwwroot/ 31 | 32 | # MSTest test Results 33 | [Tt]est[Rr]esult*/ 34 | [Bb]uild[Ll]og.* 35 | 36 | # NUNIT 37 | *.VisualState.xml 38 | TestResult.xml 39 | 40 | # Build Results of an ATL Project 41 | [Dd]ebugPS/ 42 | [Rr]eleasePS/ 43 | dlldata.c 44 | 45 | # .NET Core 46 | project.lock.json 47 | project.fragment.lock.json 48 | artifacts/ 49 | **/Properties/launchSettings.json 50 | 51 | *_i.c 52 | *_p.c 53 | *_i.h 54 | *.ilk 55 | *.meta 56 | *.obj 57 | *.pch 58 | *.pdb 59 | *.pgc 60 | *.pgd 61 | *.rsp 62 | *.sbr 63 | *.tlb 64 | *.tli 65 | *.tlh 66 | *.tmp 67 | *.tmp_proj 68 | *.log 69 | *.vspscc 70 | *.vssscc 71 | .builds 72 | *.pidb 73 | *.svclog 74 | *.scc 75 | 76 | # Chutzpah Test files 77 | _Chutzpah* 78 | 79 | # Visual C++ cache files 80 | ipch/ 81 | *.aps 82 | *.ncb 83 | *.opendb 84 | *.opensdf 85 | *.sdf 86 | *.cachefile 87 | *.VC.db 88 | *.VC.VC.opendb 89 | 90 | # Visual Studio profiler 91 | *.psess 92 | *.vsp 93 | *.vspx 94 | *.sap 95 | 96 | # TFS 2012 Local Workspace 97 | $tf/ 98 | 99 | # Guidance Automation Toolkit 100 | *.gpState 101 | 102 | # ReSharper is a .NET coding add-in 103 | _ReSharper*/ 104 | *.[Rr]e[Ss]harper 105 | *.DotSettings.user 106 | 107 | # JustCode is a .NET coding add-in 108 | .JustCode 109 | 110 | # TeamCity is a build add-in 111 | _TeamCity* 112 | 113 | # DotCover is a Code Coverage Tool 114 | *.dotCover 115 | 116 | # Visual Studio code coverage results 117 | *.coverage 118 | *.coveragexml 119 | 120 | # NCrunch 121 | _NCrunch_* 122 | .*crunch*.local.xml 123 | nCrunchTemp_* 124 | 125 | # MightyMoose 126 | *.mm.* 127 | AutoTest.Net/ 128 | 129 | # Web workbench (sass) 130 | .sass-cache/ 131 | 132 | # Installshield output folder 133 | [Ee]xpress/ 134 | 135 | # DocProject is a documentation generator add-in 136 | DocProject/buildhelp/ 137 | DocProject/Help/*.HxT 138 | DocProject/Help/*.HxC 139 | DocProject/Help/*.hhc 140 | DocProject/Help/*.hhk 141 | DocProject/Help/*.hhp 142 | DocProject/Help/Html2 143 | DocProject/Help/html 144 | 145 | # Click-Once directory 146 | publish/ 147 | 148 | # Publish Web Output 149 | *.[Pp]ublish.xml 150 | *.azurePubxml 151 | # TODO: Comment the next line if you want to checkin your web deploy settings 152 | # but database connection strings (with potential passwords) will be unencrypted 153 | *.pubxml 154 | *.publishproj 155 | 156 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 157 | # checkin your Azure Web App publish settings, but sensitive information contained 158 | # in these scripts will be unencrypted 159 | PublishScripts/ 160 | 161 | # NuGet Packages 162 | *.nupkg 163 | # The packages folder can be ignored because of Package Restore 164 | **/packages/* 165 | # except build/, which is used as an MSBuild target. 166 | !**/packages/build/ 167 | # Uncomment if necessary however generally it will be regenerated when needed 168 | #!**/packages/repositories.config 169 | # NuGet v3's project.json files produces more ignorable files 170 | *.nuget.props 171 | *.nuget.targets 172 | 173 | # Microsoft Azure Build Output 174 | csx/ 175 | *.build.csdef 176 | 177 | # Microsoft Azure Emulator 178 | ecf/ 179 | rcf/ 180 | 181 | # Windows Store app package directories and files 182 | AppPackages/ 183 | BundleArtifacts/ 184 | Package.StoreAssociation.xml 185 | _pkginfo.txt 186 | 187 | # Visual Studio cache files 188 | # files ending in .cache can be ignored 189 | *.[Cc]ache 190 | # but keep track of directories ending in .cache 191 | !*.[Cc]ache/ 192 | 193 | # Others 194 | ClientBin/ 195 | ~$* 196 | *~ 197 | *.dbmdl 198 | *.dbproj.schemaview 199 | *.jfm 200 | *.pfx 201 | *.publishsettings 202 | orleans.codegen.cs 203 | 204 | # Since there are multiple workflows, uncomment next line to ignore bower_components 205 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 206 | #bower_components/ 207 | 208 | # RIA/Silverlight projects 209 | Generated_Code/ 210 | 211 | # Backup & report files from converting an old project file 212 | # to a newer Visual Studio version. Backup files are not needed, 213 | # because we have git ;-) 214 | _UpgradeReport_Files/ 215 | Backup*/ 216 | UpgradeLog*.XML 217 | UpgradeLog*.htm 218 | 219 | # SQL Server files 220 | *.mdf 221 | *.ldf 222 | *.ndf 223 | 224 | # Business Intelligence projects 225 | *.rdl.data 226 | *.bim.layout 227 | *.bim_*.settings 228 | 229 | # Microsoft Fakes 230 | FakesAssemblies/ 231 | 232 | # GhostDoc plugin setting file 233 | *.GhostDoc.xml 234 | 235 | # Node.js Tools for Visual Studio 236 | .ntvs_analysis.dat 237 | node_modules/ 238 | 239 | # Typescript v1 declaration files 240 | typings/ 241 | 242 | # Visual Studio 6 build log 243 | *.plg 244 | 245 | # Visual Studio 6 workspace options file 246 | *.opt 247 | 248 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 249 | *.vbw 250 | 251 | # Visual Studio LightSwitch build output 252 | **/*.HTMLClient/GeneratedArtifacts 253 | **/*.DesktopClient/GeneratedArtifacts 254 | **/*.DesktopClient/ModelManifest.xml 255 | **/*.Server/GeneratedArtifacts 256 | **/*.Server/ModelManifest.xml 257 | _Pvt_Extensions 258 | 259 | # Paket dependency manager 260 | .paket/paket.exe 261 | paket-files/ 262 | 263 | # FAKE - F# Make 264 | .fake/ 265 | 266 | # JetBrains Rider 267 | .idea/ 268 | *.sln.iml 269 | 270 | # CodeRush 271 | .cr/ 272 | 273 | # Python Tools for Visual Studio (PTVS) 274 | __pycache__/ 275 | *.pyc 276 | 277 | # Cake - Uncomment if you are using it 278 | # tools/** 279 | # !tools/packages.config 280 | 281 | # Telerik's JustMock configuration file 282 | *.jmconfig 283 | 284 | # BizTalk build output 285 | *.btp.cs 286 | *.btm.cs 287 | *.odx.cs 288 | *.xsd.cs 289 | -------------------------------------------------------------------------------- /7-suave/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": ".NET Core Attach", 6 | "type": "coreclr", 7 | "request": "attach", 8 | "preLaunchTask": "run", 9 | "processId": "${command:pickProcess}" 10 | } 11 | ] 12 | } -------------------------------------------------------------------------------- /7-suave/.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=733558 3 | // for the documentation about the tasks.json format 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "taskName": "build", 8 | "command": "dotnet build", 9 | "type": "shell", 10 | "group": { 11 | "kind": "build", 12 | "isDefault": true 13 | }, 14 | "presentation": { 15 | "reveal": "silent" 16 | }, 17 | "problemMatcher": "$msCompile" 18 | }, 19 | { 20 | "taskName": "publish", 21 | "command": "dotnet publish", 22 | "dependsOn": "build", 23 | "type": "shell", 24 | "problemMatcher": [] 25 | }, 26 | { 27 | "taskName": "run", 28 | "command": "func start --script-root bin\\debug\\netstandard2.0\\publish", 29 | "dependsOn": "publish", 30 | "type": "shell", 31 | "problemMatcher": [] 32 | } 33 | ] 34 | } -------------------------------------------------------------------------------- /7-suave/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Mikhail Shilkov 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /7-suave/README.md: -------------------------------------------------------------------------------- 1 | # F# HTTP Trigger Functions for .NET Core 2.0 2 | 3 | Examples of Azure Functions with HTTP trigger, implemented in F# and running on .NET Core 2.0 with Azure Functions 2.0 runtime (currently in beta/preview). 4 | 5 | ## Running examples 6 | 7 | ``` bash 8 | dotnet restore 9 | dotnet build 10 | dotnet publish 11 | cd bin\debug\netstandard2.0\publish 12 | func host start 13 | ``` 14 | 15 | or just execute `run` command from Visual Studio Code. 16 | 17 | ## Simple HTTP 18 | 19 | Minimal example of HTTP Trigger in F# 20 | 21 | Sample URL: http://localhost:7071/api/simple?name=User 22 | 23 | Response: `Hi, User` 24 | 25 | ## Suave HTTP 26 | 27 | Example using [Suave](https://suave.io/) F#-friendly web library 28 | 29 | Sample URL: http://localhost:7071/api/suave/goodbye 30 | 31 | Response: `Good bye GET` 32 | 33 | Based on [Tamizhvendan](https://github.com/tamizhvendan)'s [`Suave.Azure.Functions`](https://github.com/tamizhvendan/Suave.Azure.Functions) 34 | 35 | ## Other Links 36 | 37 | Blog post [Develop Azure Functions on any platform](http://blogs.msdn.microsoft.com/appserviceteam/2017/09/25/develop-azure-functions-on-any-platform/) 38 | -------------------------------------------------------------------------------- /7-suave/SuaveApp.fsproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard2.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | PreserveNewest 23 | 24 | 25 | PreserveNewest 26 | 27 | 28 | PreserveNewest 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /7-suave/SuaveHttp/Adapter/Context.fs: -------------------------------------------------------------------------------- 1 | module Suave.Azure.Functions.Context 2 | 3 | open Request 4 | open Response 5 | open Suave 6 | open System.Net.Http 7 | open System.Net 8 | 9 | let runWebPart (app : WebPart) (httpRequestMessage : HttpRequestMessage) = async { 10 | let! req = suaveHttpRequest httpRequestMessage 11 | let! ctx = app { HttpContext.empty with request = req } 12 | match ctx with 13 | | Some ctx -> 14 | return httpResponseMessage ctx.response 15 | | None -> 16 | let res = new HttpResponseMessage() 17 | res.StatusCode <- HttpStatusCode.NotFound 18 | return res 19 | } -------------------------------------------------------------------------------- /7-suave/SuaveHttp/Adapter/Request.fs: -------------------------------------------------------------------------------- 1 | module Suave.Azure.Functions.Request 2 | 3 | open Suave.Http 4 | open System.Net.Http 5 | open System.Net.Http.Headers 6 | 7 | let suaveHttpMethod (httpMethod : HttpMethod) = 8 | match httpMethod.Method with 9 | | "GET" -> HttpMethod.GET 10 | | "PUT" -> HttpMethod.PUT 11 | | "POST" -> HttpMethod.POST 12 | | "DELETE" -> HttpMethod.DELETE 13 | | "PATCH" -> HttpMethod.PATCH 14 | | "HEAD" -> HttpMethod.HEAD 15 | | "TRACE" -> HttpMethod.TRACE 16 | | "CONNECT" -> HttpMethod.CONNECT 17 | | "OPTIONS" -> HttpMethod.OPTIONS 18 | | x -> HttpMethod.OTHER x 19 | 20 | let httpMethod (suaveHttpMethod : Suave.Http.HttpMethod) = 21 | match suaveHttpMethod with 22 | | OTHER _ -> 23 | None 24 | | _ -> 25 | let method : System.String = suaveHttpMethod |> string 26 | let normalized = method.ToLowerInvariant() 27 | string(System.Char.ToUpper(normalized.[0])) + normalized.Substring(1) 28 | |> HttpMethod |> Some 29 | 30 | let suaveHttpRequestHeaders (httpRequestHeaders : Headers.HttpRequestHeaders) = 31 | httpRequestHeaders 32 | |> Seq.collect (fun h -> h.Value |> Seq.map (fun v -> (h.Key, v))) 33 | |> Seq.toList 34 | 35 | let httpRequestHeaders (suaveHttpRequestHeaders : (string * string) list) (headers : HttpRequestHeaders) = 36 | suaveHttpRequestHeaders |> List.iter headers.Add 37 | headers 38 | 39 | let suaveRawForm (content : HttpContent) = async { 40 | if isNull content then 41 | return Array.empty 42 | else 43 | return! content.ReadAsByteArrayAsync() |> Async.AwaitTask 44 | } 45 | 46 | let httpContent (rawForm : byte[]) = 47 | new ByteArrayContent(rawForm) :> HttpContent 48 | 49 | let suaveRawQuery (requestUri : System.Uri) = 50 | if requestUri.Query.Length > 1 then 51 | requestUri.Query.Substring(1) 52 | else 53 | "" 54 | 55 | let suaveHttpRequest (httpRequestMessage : HttpRequestMessage) = async { 56 | let! rawForm = suaveRawForm httpRequestMessage.Content 57 | return { 58 | HttpRequest.empty with 59 | headers = suaveHttpRequestHeaders httpRequestMessage.Headers 60 | url = httpRequestMessage.RequestUri 61 | rawForm = rawForm 62 | rawQuery = suaveRawQuery httpRequestMessage.RequestUri 63 | ``method`` = suaveHttpMethod httpRequestMessage.Method 64 | host = httpRequestMessage.RequestUri.Host 65 | } 66 | } 67 | 68 | let httpRequestMessage (suaveHttpRequest : HttpRequest) = 69 | let req = new HttpRequestMessage() 70 | httpRequestHeaders suaveHttpRequest.headers req.Headers |> ignore 71 | req.RequestUri <- suaveHttpRequest.url 72 | req.Content <- new ByteArrayContent(suaveHttpRequest.rawForm) 73 | req.Method <- defaultArg (httpMethod suaveHttpRequest.method) (new HttpMethod("Unknown")) 74 | req -------------------------------------------------------------------------------- /7-suave/SuaveHttp/Adapter/Response.fs: -------------------------------------------------------------------------------- 1 | module Suave.Azure.Functions.Response 2 | 3 | open System.Net 4 | open Suave.Http 5 | open System.Net.Http 6 | open System.Net.Http.Headers 7 | 8 | let httpStatusCode (httpCode : HttpCode) : HttpStatusCode = 9 | LanguagePrimitives.EnumOfValue httpCode.code 10 | 11 | let suaveHttpCode (httpStatusCode : HttpStatusCode) = 12 | match LanguagePrimitives.EnumToValue httpStatusCode |> HttpCode.tryParse with 13 | | Choice1Of2 httpCode -> Some httpCode 14 | | _ -> None 15 | 16 | let suaveHttpResponseHeaders (httpResponseHeaders : HttpResponseHeaders) = 17 | httpResponseHeaders 18 | |> Seq.map (fun h -> h.Key, h.Value) 19 | |> Seq.collect (fun (k,vs) -> vs |> Seq.map (fun v -> (k,v))) 20 | |> Seq.toList 21 | 22 | let httpResponseMessage (httpResult : HttpResult) = 23 | let content = function 24 | | Bytes c -> c 25 | | _ -> Array.empty 26 | 27 | let res = new HttpResponseMessage() 28 | let content = new ByteArrayContent(content httpResult.content) 29 | httpResult.headers 30 | |> List.iter (fun (name,value) -> 31 | try 32 | match name with 33 | | "Content-Type" -> 34 | content.Headers.ContentType <- new Headers.MediaTypeHeaderValue(value) 35 | | _ -> content.Headers.Add(name,value) 36 | with 37 | | ex -> 38 | failwithf "Error while setting response header '%s' with the value '%s' :%s" name value ex.Message) 39 | 40 | res.Content <- content 41 | res.StatusCode <- HttpStatusCode.OK// httpStatusCode httpResult.status 42 | res 43 | 44 | let suaveHttpResult (httpResponseMessage : HttpResponseMessage) = async { 45 | let statusCode = 46 | match suaveHttpCode httpResponseMessage.StatusCode with 47 | | Some x -> x 48 | | _ -> HTTP_502 49 | let! content = async { 50 | if isNull httpResponseMessage.Content then 51 | return NullContent 52 | else 53 | let! res = httpResponseMessage.Content.ReadAsByteArrayAsync() |> Async.AwaitTask 54 | return Bytes res 55 | } 56 | 57 | return { 58 | status = { code = statusCode.code; reason = statusCode.reason } 59 | headers = suaveHttpResponseHeaders httpResponseMessage.Headers 60 | content = content 61 | writePreamble = false 62 | } 63 | } -------------------------------------------------------------------------------- /7-suave/SuaveHttp/SuaveHttp.fs: -------------------------------------------------------------------------------- 1 | namespace SuaveApp 2 | 3 | module App = 4 | open Suave 5 | open Suave.Successful 6 | open Suave.Operators 7 | open Suave.Filters 8 | 9 | let app = 10 | GET >=> choose 11 | [ path "/api/suave/hello" >=> OK "Hello GET" 12 | path "/api/suave/goodbye" >=> OK "Good bye GET" ] 13 | 14 | module Http = 15 | open Suave.Azure.Functions.Context 16 | 17 | let run req = 18 | req |> runWebPart App.app |> Async.StartAsTask -------------------------------------------------------------------------------- /7-suave/SuaveHttp/function.json: -------------------------------------------------------------------------------- 1 | { 2 | "bindings": [ 3 | { 4 | "type": "httpTrigger", 5 | "methods": ["get"], 6 | "authLevel": "anonymous", 7 | "name": "req", 8 | "route": "suave/{*anything}" 9 | } 10 | ], 11 | "scriptFile": "../bin/SuaveApp.dll", 12 | "entryPoint": "SuaveApp.Http.run" 13 | } -------------------------------------------------------------------------------- /7-suave/host.json: -------------------------------------------------------------------------------- 1 | { 2 | } -------------------------------------------------------------------------------- /7-suave/local.settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "IsEncrypted": false, 3 | "Values": { 4 | "AzureWebJobsStorage": "UseDevelopmentStorage=true" 5 | } 6 | } -------------------------------------------------------------------------------- /8-paket/.paket/Paket.Restore.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | $(MSBuildAllProjects);$(MSBuildThisFileFullPath) 8 | 9 | true 10 | $(MSBuildThisFileDirectory) 11 | $(MSBuildThisFileDirectory)..\ 12 | $(PaketRootPath)paket-files\paket.restore.cached 13 | $(PaketRootPath)paket.lock 14 | /Library/Frameworks/Mono.framework/Commands/mono 15 | mono 16 | 17 | $(PaketRootPath)paket.exe 18 | $(PaketToolsPath)paket.exe 19 | "$(PaketExePath)" 20 | $(MonoPath) --runtime=v4.0.30319 "$(PaketExePath)" 21 | $(PaketRootPath)paket.bootstrapper.exe 22 | $(PaketToolsPath)paket.bootstrapper.exe 23 | "$(PaketBootStrapperExePath)" 24 | $(MonoPath) --runtime=v4.0.30319 "$(PaketBootStrapperExePath)" 25 | 26 | 27 | 28 | 29 | true 30 | true 31 | 32 | 33 | 34 | 35 | 36 | 37 | true 38 | $(NoWarn);NU1603 39 | 40 | 41 | 42 | 43 | /usr/bin/shasum $(PaketRestoreCacheFile) | /usr/bin/awk '{ print $1 }' 44 | /usr/bin/shasum $(PaketLockFilePath) | /usr/bin/awk '{ print $1 }' 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | $([System.IO.File]::ReadAllText('$(PaketRestoreCacheFile)')) 58 | $([System.IO.File]::ReadAllText('$(PaketLockFilePath)')) 59 | true 60 | false 61 | true 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | $(MSBuildProjectDirectory)\obj\$(MSBuildProjectFile).paket.references.cached 71 | 72 | $(MSBuildProjectFullPath).paket.references 73 | 74 | $(MSBuildProjectDirectory)\$(MSBuildProjectName).paket.references 75 | 76 | $(MSBuildProjectDirectory)\paket.references 77 | $(MSBuildProjectDirectory)\obj\$(MSBuildProjectFile).$(TargetFramework).paket.resolved 78 | true 79 | references-file-or-cache-not-found 80 | 81 | 82 | 83 | 84 | $([System.IO.File]::ReadAllText('$(PaketReferencesCachedFilePath)')) 85 | $([System.IO.File]::ReadAllText('$(PaketOriginalReferencesFilePath)')) 86 | references-file 87 | false 88 | 89 | 90 | 91 | 92 | false 93 | 94 | 95 | 96 | 97 | true 98 | target-framework '$(TargetFramework)' 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | $([System.String]::Copy('%(PaketReferencesFileLines.Identity)').Split(',')[0]) 116 | $([System.String]::Copy('%(PaketReferencesFileLines.Identity)').Split(',')[1]) 117 | 118 | 119 | %(PaketReferencesFileLinesInfo.PackageVersion) 120 | 121 | 122 | 123 | 124 | $(MSBuildProjectDirectory)/obj/$(MSBuildProjectFile).paket.clitools 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | $([System.String]::Copy('%(PaketCliToolFileLines.Identity)').Split(',')[0]) 134 | $([System.String]::Copy('%(PaketCliToolFileLines.Identity)').Split(',')[1]) 135 | 136 | 137 | %(PaketCliToolFileLinesInfo.PackageVersion) 138 | 139 | 140 | 141 | 142 | $(MSBuildProjectDirectory)/obj/$(MSBuildProjectFile).NuGet.Config 143 | 144 | 145 | 146 | 147 | 148 | 149 | false 150 | 151 | 152 | 153 | 154 | 155 | <_NuspecFilesNewLocation Include="$(BaseIntermediateOutputPath)$(Configuration)\*.nuspec"/> 156 | 157 | 158 | 159 | $(MSBuildProjectDirectory)/$(MSBuildProjectFile) 160 | true 161 | false 162 | true 163 | $(BaseIntermediateOutputPath)$(Configuration) 164 | $(BaseIntermediateOutputPath) 165 | 166 | 167 | 168 | <_NuspecFiles Include="$(AdjustedNuspecOutputPath)\*.nuspec"/> 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 221 | 222 | 263 | 264 | 265 | 266 | -------------------------------------------------------------------------------- /8-paket/.paket/paket.bootstrapper.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mikhailshilkov/azure-functions-fsharp-examples/24501c809b1998ab069ab23802862084505f5390/8-paket/.paket/paket.bootstrapper.exe -------------------------------------------------------------------------------- /8-paket/.paket/paket.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mikhailshilkov/azure-functions-fsharp-examples/24501c809b1998ab069ab23802862084505f5390/8-paket/.paket/paket.exe -------------------------------------------------------------------------------- /8-paket/.paket/paket.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | true 7 | $(MSBuildThisFileDirectory) 8 | $(MSBuildThisFileDirectory)..\ 9 | $(PaketRootPath)paket.lock 10 | $(PaketRootPath)paket-files\paket.restore.cached 11 | /Library/Frameworks/Mono.framework/Commands/mono 12 | mono 13 | 14 | 15 | 16 | 17 | $(PaketRootPath)paket.exe 18 | $(PaketToolsPath)paket.exe 19 | "$(PaketExePath)" 20 | $(MonoPath) --runtime=v4.0.30319 "$(PaketExePath)" 21 | 22 | 23 | 24 | 25 | 26 | $(MSBuildProjectFullPath).paket.references 27 | 28 | 29 | 30 | 31 | $(MSBuildProjectDirectory)\$(MSBuildProjectName).paket.references 32 | 33 | 34 | 35 | 36 | $(MSBuildProjectDirectory)\paket.references 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | $(PaketCommand) restore --references-file "$(PaketReferences)" 49 | 50 | RestorePackages; $(BuildDependsOn); 51 | 52 | 53 | 54 | true 55 | 56 | 57 | 58 | $([System.IO.File]::ReadAllText('$(PaketRestoreCacheFile)')) 59 | $([System.IO.File]::ReadAllText('$(PaketLockFilePath)')) 60 | true 61 | false 62 | true 63 | 64 | 65 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /8-paket/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": ".NET Core Attach", 6 | "type": "coreclr", 7 | "request": "attach", 8 | "preLaunchTask": "run", 9 | "processId": "${command:pickProcess}" 10 | } 11 | ] 12 | } -------------------------------------------------------------------------------- /8-paket/.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=733558 3 | // for the documentation about the tasks.json format 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "label": "restore", 8 | "command": ".paket\\paket.exe install", 9 | "type": "shell", 10 | "problemMatcher": [] 11 | }, 12 | { 13 | "label": "build", 14 | "command": "dotnet build", 15 | "type": "shell", 16 | "group": { 17 | "kind": "build", 18 | "isDefault": true 19 | }, 20 | "presentation": { 21 | "reveal": "silent" 22 | }, 23 | "problemMatcher": "$msCompile" 24 | }, 25 | { 26 | "label": "publish", 27 | "command": "dotnet publish", 28 | "dependsOn": "build", 29 | "type": "shell", 30 | "problemMatcher": [] 31 | }, 32 | { 33 | "label": "run", 34 | "command": "cd PaketFunctions;func start --script-root bin\\debug\\netstandard2.0\\publish", 35 | "dependsOn": "publish", 36 | "type": "shell", 37 | "problemMatcher": [] 38 | } 39 | ] 40 | } -------------------------------------------------------------------------------- /8-paket/PaketFunctions.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.25420.1 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PaketFunctions", "PaketFunctions\PaketFunctions.fsproj", "{13D22BA7-F66F-48E6-A362-81780864339F}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {13D22BA7-F66F-48E6-A362-81780864339F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {13D22BA7-F66F-48E6-A362-81780864339F}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {13D22BA7-F66F-48E6-A362-81780864339F}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {13D22BA7-F66F-48E6-A362-81780864339F}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | EndGlobal 23 | -------------------------------------------------------------------------------- /8-paket/PaketFunctions/PaketFunctions.fsproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | Library 6 | 7 | 8 | 9 | 10 | 11 | 12 | PreserveNewest 13 | 14 | 15 | PreserveNewest 16 | 17 | 18 | PreserveNewest 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /8-paket/PaketFunctions/PaketHttp/PaketHttp.fs: -------------------------------------------------------------------------------- 1 | namespace PaketFunctions 2 | 3 | open Microsoft.AspNetCore.Mvc 4 | open Microsoft.AspNetCore.Http 5 | open Microsoft.Azure.WebJobs.Host 6 | 7 | module PaketHttp = 8 | let run(req: HttpRequest, log: TraceWriter) = 9 | log.Info("F# HTTP trigger function processed a request.") 10 | 11 | ContentResult(Content = "You can use Paket in Function Apps", ContentType = "text/html") 12 | -------------------------------------------------------------------------------- /8-paket/PaketFunctions/PaketHttp/function.json: -------------------------------------------------------------------------------- 1 | { 2 | "bindings": [ 3 | { 4 | "type": "httpTrigger", 5 | "methods": ["get"], 6 | "authLevel": "anonymous", 7 | "name": "req", 8 | "route": "paket" 9 | } 10 | ], 11 | "scriptFile": "../bin/PaketFunctions.dll", 12 | "entryPoint": "PaketFunctions.PaketHttp.run" 13 | } -------------------------------------------------------------------------------- /8-paket/PaketFunctions/host.json: -------------------------------------------------------------------------------- 1 | { 2 | } -------------------------------------------------------------------------------- /8-paket/PaketFunctions/local.settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "IsEncrypted": false, 3 | "Values": { 4 | "AzureWebJobsStorage": "UseDevelopmentStorage=true" 5 | } 6 | } -------------------------------------------------------------------------------- /8-paket/PaketFunctions/paket.references: -------------------------------------------------------------------------------- 1 | FSharp.Core 2 | Microsoft.NET.Sdk.Functions 3 | Microsoft.AspNetCore.Mvc.Core -------------------------------------------------------------------------------- /8-paket/paket.dependencies: -------------------------------------------------------------------------------- 1 | source https://www.nuget.org/api/v2 2 | 3 | framework: >= netstandard2.0 4 | nuget FSharp.Core 5 | nuget Microsoft.NET.Sdk.Functions 6 | nuget Microsoft.AspNetCore.Mvc.Core -------------------------------------------------------------------------------- /9-attributes/.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /9-attributes/.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | bld/ 21 | [Bb]in/ 22 | [Oo]bj/ 23 | [Ll]og/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | project.fragment.lock.json 46 | artifacts/ 47 | 48 | *_i.c 49 | *_p.c 50 | *_i.h 51 | *.ilk 52 | *.meta 53 | *.obj 54 | *.pch 55 | *.pdb 56 | *.pgc 57 | *.pgd 58 | *.rsp 59 | *.sbr 60 | *.tlb 61 | *.tli 62 | *.tlh 63 | *.tmp 64 | *.tmp_proj 65 | *.log 66 | *.vspscc 67 | *.vssscc 68 | .builds 69 | *.pidb 70 | *.svclog 71 | *.scc 72 | 73 | # Chutzpah Test files 74 | _Chutzpah* 75 | 76 | # Visual C++ cache files 77 | ipch/ 78 | *.aps 79 | *.ncb 80 | *.opendb 81 | *.opensdf 82 | *.sdf 83 | *.cachefile 84 | *.VC.db 85 | *.VC.VC.opendb 86 | 87 | # Visual Studio profiler 88 | *.psess 89 | *.vsp 90 | *.vspx 91 | *.sap 92 | 93 | # TFS 2012 Local Workspace 94 | $tf/ 95 | 96 | # Guidance Automation Toolkit 97 | *.gpState 98 | 99 | # ReSharper is a .NET coding add-in 100 | _ReSharper*/ 101 | *.[Rr]e[Ss]harper 102 | *.DotSettings.user 103 | 104 | # JustCode is a .NET coding add-in 105 | .JustCode 106 | 107 | # TeamCity is a build add-in 108 | _TeamCity* 109 | 110 | # DotCover is a Code Coverage Tool 111 | *.dotCover 112 | 113 | # NCrunch 114 | _NCrunch_* 115 | .*crunch*.local.xml 116 | nCrunchTemp_* 117 | 118 | # MightyMoose 119 | *.mm.* 120 | AutoTest.Net/ 121 | 122 | # Web workbench (sass) 123 | .sass-cache/ 124 | 125 | # Installshield output folder 126 | [Ee]xpress/ 127 | 128 | # DocProject is a documentation generator add-in 129 | DocProject/buildhelp/ 130 | DocProject/Help/*.HxT 131 | DocProject/Help/*.HxC 132 | DocProject/Help/*.hhc 133 | DocProject/Help/*.hhk 134 | DocProject/Help/*.hhp 135 | DocProject/Help/Html2 136 | DocProject/Help/html 137 | 138 | # Click-Once directory 139 | publish/ 140 | 141 | # Publish Web Output 142 | *.[Pp]ublish.xml 143 | *.azurePubxml 144 | # TODO: Comment the next line if you want to checkin your web deploy settings 145 | # but database connection strings (with potential passwords) will be unencrypted 146 | #*.pubxml 147 | *.publishproj 148 | 149 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 150 | # checkin your Azure Web App publish settings, but sensitive information contained 151 | # in these scripts will be unencrypted 152 | PublishScripts/ 153 | 154 | # NuGet Packages 155 | *.nupkg 156 | # The packages folder can be ignored because of Package Restore 157 | **/packages/* 158 | # except build/, which is used as an MSBuild target. 159 | !**/packages/build/ 160 | # Uncomment if necessary however generally it will be regenerated when needed 161 | #!**/packages/repositories.config 162 | # NuGet v3's project.json files produces more ignoreable files 163 | *.nuget.props 164 | *.nuget.targets 165 | 166 | # Microsoft Azure Build Output 167 | csx/ 168 | *.build.csdef 169 | 170 | # Microsoft Azure Emulator 171 | ecf/ 172 | rcf/ 173 | 174 | # Windows Store app package directories and files 175 | AppPackages/ 176 | BundleArtifacts/ 177 | Package.StoreAssociation.xml 178 | _pkginfo.txt 179 | 180 | # Visual Studio cache files 181 | # files ending in .cache can be ignored 182 | *.[Cc]ache 183 | # but keep track of directories ending in .cache 184 | !*.[Cc]ache/ 185 | 186 | # Others 187 | ClientBin/ 188 | ~$* 189 | *~ 190 | *.dbmdl 191 | *.dbproj.schemaview 192 | *.jfm 193 | *.pfx 194 | *.publishsettings 195 | node_modules/ 196 | orleans.codegen.cs 197 | 198 | # Since there are multiple workflows, uncomment next line to ignore bower_components 199 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 200 | #bower_components/ 201 | 202 | # RIA/Silverlight projects 203 | Generated_Code/ 204 | 205 | # Backup & report files from converting an old project file 206 | # to a newer Visual Studio version. Backup files are not needed, 207 | # because we have git ;-) 208 | _UpgradeReport_Files/ 209 | Backup*/ 210 | UpgradeLog*.XML 211 | UpgradeLog*.htm 212 | 213 | # SQL Server files 214 | *.mdf 215 | *.ldf 216 | 217 | # Business Intelligence projects 218 | *.rdl.data 219 | *.bim.layout 220 | *.bim_*.settings 221 | 222 | # Microsoft Fakes 223 | FakesAssemblies/ 224 | 225 | # GhostDoc plugin setting file 226 | *.GhostDoc.xml 227 | 228 | # Node.js Tools for Visual Studio 229 | .ntvs_analysis.dat 230 | 231 | # Visual Studio 6 build log 232 | *.plg 233 | 234 | # Visual Studio 6 workspace options file 235 | *.opt 236 | 237 | # Visual Studio LightSwitch build output 238 | **/*.HTMLClient/GeneratedArtifacts 239 | **/*.DesktopClient/GeneratedArtifacts 240 | **/*.DesktopClient/ModelManifest.xml 241 | **/*.Server/GeneratedArtifacts 242 | **/*.Server/ModelManifest.xml 243 | _Pvt_Extensions 244 | 245 | # Paket dependency manager 246 | .paket/paket.exe 247 | paket-files/ 248 | 249 | # FAKE - F# Make 250 | .fake/ 251 | 252 | # JetBrains Rider 253 | .idea/ 254 | *.sln.iml 255 | 256 | # CodeRush 257 | .cr/ 258 | 259 | # Python Tools for Visual Studio (PTVS) 260 | __pycache__/ 261 | *.pyc -------------------------------------------------------------------------------- /9-attributes/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": ".NET Core Attach", 6 | "type": "coreclr", 7 | "request": "attach", 8 | "preLaunchTask": "run", 9 | "processId": "${command:pickProcess}" 10 | } 11 | ] 12 | } -------------------------------------------------------------------------------- /9-attributes/.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=733558 3 | // for the documentation about the tasks.json format 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "taskName": "build", 8 | "command": "dotnet build", 9 | "type": "shell", 10 | "group": { 11 | "kind": "build", 12 | "isDefault": true 13 | }, 14 | "presentation": { 15 | "reveal": "silent" 16 | }, 17 | "problemMatcher": "$msCompile" 18 | }, 19 | { 20 | "taskName": "publish", 21 | "command": "dotnet publish", 22 | "dependsOn": "build", 23 | "type": "shell", 24 | "problemMatcher": [] 25 | }, 26 | { 27 | "taskName": "run", 28 | "command": "func start --script-root bin\\debug\\netstandard2.0\\publish", 29 | "dependsOn": "publish", 30 | "type": "shell", 31 | "problemMatcher": [] 32 | } 33 | ] 34 | } -------------------------------------------------------------------------------- /9-attributes/AttributeBasedApp.fsproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard2.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | PreserveNewest 19 | 20 | 21 | PreserveNewest 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /9-attributes/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Donna Malayeri 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /9-attributes/PrecompiledHttp.fs: -------------------------------------------------------------------------------- 1 | namespace AttributeBasedApp 2 | 3 | open Microsoft.AspNetCore.Mvc 4 | open Microsoft.AspNetCore.Http 5 | open Microsoft.Azure.WebJobs 6 | open Microsoft.Azure.WebJobs.Host 7 | open Microsoft.Azure.WebJobs.Extensions.Http 8 | 9 | module AttributeBased = 10 | 11 | [] 12 | let run([] req: HttpRequest, log: TraceWriter, context: ExecutionContext) = 13 | log.Info("F# HTTP trigger function processed a request.") 14 | log.Info context.FunctionDirectory 15 | 16 | ContentResult(Content = "function.json was successfully auto-generated.", ContentType = "text/html") 17 | -------------------------------------------------------------------------------- /9-attributes/host.json: -------------------------------------------------------------------------------- 1 | { 2 | } -------------------------------------------------------------------------------- /9-attributes/local.settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "IsEncrypted": false, 3 | "Values": { 4 | "AzureWebJobsStorage": "UseDevelopmentStorage=true" 5 | } 6 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Mikhail Shilkov 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Azure Functions in F# 2 | 3 | Examples of Azure Functions written in F#. Created for demos at 4 | [FSharping meetup](https://www.meetup.com/FSharping/events/244137693/). 5 | 6 | ### Prerequisites 7 | 8 | - Azure subscription (their is [a free trial for Function Apps](https://functions.azure.com/try) but 9 | F# support seems not optimal there) 10 | 11 | - Node.js version 8.x with NPM 12 | 13 | - Editor (I use Visual Studio Code with Ionide plugin) 14 | 15 | - Azure Storage Explorer for working with Blobs, Queues and Tables 16 | 17 | ## 1. Function App Created in the Portal 18 | 19 | Go to Azure Portal, click `New` button and search for Function App. Click through the wizard 20 | to create a new Function App. 21 | 22 | Open the app when it's created, add a new function. Pick `Timer` as scenario and F# as language. 23 | 24 | Replace the contents of `function.json` and `run.fsx` with files from `1-portal-timer` folder. 25 | 26 | Observe the logs to see that the function runs every minute and outputs the message about 27 | the meetup duration. 28 | 29 | Explore `function.json` file and its syntax for trigger definition. 30 | 31 | Explore the portal functionality around Functions. 32 | 33 | 34 | ## 2. HTTP Function Created in the Portal 35 | 36 | Create another function in the same app, this time use `HttpTrigger F#` template. Explore different 37 | available templates while doing so. 38 | 39 | Delete `project.json` and `project.json.lock` files and copy the contents of `function.json` and `run.fsx` 40 | from `2-portal-http` folder. 41 | 42 | Go to `Test` tab on the right, and type `{ "name@": "FSharping" }` in Request body. Click `Run` button 43 | and check that `Hello FSharping` is returned back. 44 | 45 | Note `name@` parameter name. That's because we used F# record type to define the request body, and that's 46 | how default serialization works for them. This problem will be solved in example 8. 47 | 48 | Explore `function.json` file and its syntax for HTTP trigger and output binding definitions. 49 | 50 | Note how function is defined in small-case `run`, and that it's in curried form. This is supported by 51 | Functions, but not required. 52 | 53 | 54 | ## 3. HTTP Function Templating HTML from Blob Storage 55 | 56 | Follow the same steps to create yet another F# HTTP function, but use files from `3-portal-http-html` 57 | folder. 58 | 59 | In the Blob Storage account that you selected while creating the Function App, add a container called 60 | `html`. Put two html files from the folder into this container. 61 | 62 | Now, in the portal, click `Get function URL` button and copy paste it to your browser. Replace parameters 63 | in the URL: `{filename}` with `hello` and `{name}` with `FSharping`. Load the URL in the browser and 64 | make sure that HTML with `Hello FSharping` is rendered. Replace `hello` with `awesome` and load it again, 65 | so see that HTML has changed. 66 | 67 | This works due to an input binding to Blob Storage defined in `function.json`. Explore the syntax to 68 | define HTTP route for the trigger, and templated Blob input binding. See how the function code glues 69 | them together. 70 | 71 | 72 | ## 4. Function Created with CLI 73 | 74 | Azure Portal is great to get started, but it's not the most developer-friendly way to write code. 75 | Instead, we will create all the remaining functions locally on dev machine, and deploy it to Azure 76 | from there. 77 | 78 | Run the following command to install Azure Functions CLI and runtime on your machine: 79 | 80 | ``` bash 81 | npm install -g azure-functions-core-tools 82 | ``` 83 | 84 | After it's done, type `func` command to make sure the installation was successful. 85 | 86 | Run `func init` to initialize a new Function App. 87 | 88 | Run `func new`, pick `F#` in choice menu, then `HttpTrigger`, then give it a name. 89 | 90 | CLI will generate the files required for your new function. Browse through the files to see what 91 | was generated. 92 | 93 | Run `func host start` to run your function locally. Runtime will run an HTTP server and will host 94 | your function on port `7071`. 95 | 96 | Run the following command in another command line window (replace the function name if needed): 97 | 98 | ``` bash 99 | curl http://localhost:7071/api/cli-http?name=fsharping 100 | ``` 101 | 102 | Check that response `200 OK` with body `Hello fsharping` was returned. 103 | 104 | Open the Function App folder in Visual Studio Code editor (`code .` command). Notice the multiple 105 | red squigglies while viewing `fsx` file. That's because Functions runtime imports several libraries 106 | "auto-magically" while running, but Code doesn't know about them. 107 | 108 | To fix those, copy the following headers to the top of `fsx` (replace `username` with your user): 109 | 110 | ``` fs 111 | #if INTERACTIVE 112 | 113 | open System 114 | 115 | #I @"C:/Users/username/AppData/Roaming/npm/node_modules/azure-functions-core-tools/bin/" 116 | 117 | #r "Microsoft.Azure.Webjobs.Host.dll" 118 | open Microsoft.Azure.WebJobs.Host 119 | 120 | #r "System.Net.Http.Formatting.dll" 121 | #r "System.Web.Http.dll" 122 | #r "System.Net.Http.dll" 123 | #r "Newtonsoft.Json.dll" 124 | 125 | #else 126 | 127 | #r "System.Net.Http" 128 | #r "Newtonsoft.Json" 129 | 130 | #endif 131 | ``` 132 | 133 | Make sure errors are gone from VS Code. 134 | 135 | 136 | ## 5. Precompiled Function 137 | 138 | Scripts are nice for dynamic exploration, but I prefer precompiled libraries for more complex 139 | applications. The same applies to Azure Functions: you can deploy normal Class Libraries as 140 | functions. 141 | 142 | Current version of CLI doesn't support creating precompiled functions. It does support running 143 | and deploying them! 144 | 145 | For the rest of the demos, I chose to use cross-platform version 2 of Functions runtime, which 146 | is currently in beta. To follow along: 147 | 148 | - Go to the portal and create a new Function App. Click on its name, then go to `Function app settings` 149 | and switch the runtime version toggle to `beta` 150 | 151 | - Install core version of CLI and runtime by running `npm install -g azure-functions-core-tools@core` 152 | 153 | Now, explore the code in `5-precompiled` folder in Code. Note `PrecompiledApp.fsproj` file with 154 | a reference to `Microsoft.AspNetCore.Mvc.Core` and `Microsoft.NET.Sdk.Functions` packages. 155 | 156 | `PrecompiledHttp.fs` contains the module with function definition. It's using ASP.NET Core classes. 157 | 158 | `function.json` file is still present, but now it contains `scriptFile` and `entryPoint` attributes. 159 | 160 | Run the following commands to build, publish and run your Function App locally, all from the root 161 | folder of this sample: 162 | 163 | ``` bash 164 | dotnet restore 165 | dotnet build 166 | dotnet publish 167 | func start func start --script-root bin\\debug\\netstandard2.0\\publish 168 | ``` 169 | 170 | Alternatively, just execute `run` command in Visual Studio Code. 171 | 172 | Execute `curl http://localhost:7071/api/precompiled` or open this URL in the browser to make sure 173 | that the App is running. 174 | 175 | The cool part is that debugging is also supported! Put a breakpoint on `log.Info...` line with F9, 176 | then press F5, choose `dotnet.exe` process to attach to and request the URL again. The breakpoint 177 | should hit. 178 | 179 | When you are ready, publish your Function to Azure by running 180 | 181 | ``` bash 182 | func azure functionapp publish 183 | ``` 184 | 185 | `5-precompiled-full-framework` shows the same example but targeting full .NET 4.6.2 framework rather 186 | than .NET Standard 2.0. 187 | 188 | ## 6. Precompiled Timer 189 | 190 | Just another example of a precompiled function, this time with Timer trigger. 191 | 192 | ## 6b. Precompiled HTTP to Service Bus topic function 193 | 194 | And yet another example of a precompiled function, this time with an HTTP trigger and an output binding to an Azure Service Bus topic. 195 | 196 | ## 7. Suave Function 197 | 198 | What can we do with precompiled functions? Well, we can do a lot, for example use our favourite 199 | F# libraries. 200 | 201 | Open the folder `6-suave`. This demo shows the use of [Suave](http://suave.io) library to process 202 | HTTP requests. 203 | 204 | `function.json` now defines a wildcard route to redirect all requests starting with `/api/suave` to the 205 | function. 206 | 207 | `SuaveHttp.fs` has a definition of an app which will look familiar to all Suave users: 208 | 209 | ``` fs 210 | let app = 211 | GET >=> choose 212 | [ path "/api/suave/hello" >=> OK "Hello GET" 213 | path "/api/suave/goodbye" >=> OK "Good bye GET" ] 214 | ``` 215 | 216 | The function is then just a one-liner wiring Suave app into the pipeline. 217 | 218 | Run the application and request a URL `http://localhost:7071/api/suave/hello` to see it in action. 219 | 220 | This sample is very simple, but you can do lots of powerful stuff with Suave! 221 | 222 | ## 8. Paket 223 | 224 | Once your Function App becomes bigger and you start using multiple F# 225 | projects, it makes sense to switch to Paket package manager. 226 | 227 | It is totally possible to use 228 | [Paket](https://fsprojects.github.io/Paket/) 229 | with Azure Functions. There isn't 230 | much specific to Azure Functions, really. Here is an example of 231 | `paket.dependecies` file 232 | 233 | ``` 234 | source https://www.nuget.org/api/v2 235 | 236 | framework: >= netstandard2.0 237 | nuget FSharp.Core 238 | nuget Microsoft.NET.Sdk.Functions 239 | nuget Microsoft.AspNetCore.Mvc.Core 240 | ``` 241 | 242 | ## 9. Attribute-Based Functions 243 | 244 | Up until now, we were writing `function.json` files manually for each function. This is not very 245 | tedious, but error prone. There is an alternative programming model where these files are 246 | auto-generated by Functions SDK. 247 | 248 | This programming model is based on attributes, which are similar to WebJobs SDK attributes. 249 | You can find an example of HTTP function with attributes in `7-attributes` folder. 250 | 251 | Note that there's no `function.json` file in the project. Instead, the function declaration is 252 | decorated with attributes: 253 | 254 | ``` fs 255 | [] 256 | let run([] req: HttpRequest, log: TraceWriter) 257 | ``` 258 | 259 | The same development flow still works. Once you run `dotnet build`, a new `function.json` file 260 | will be generated and place to `bin` folder. Function runtime will be able to use it to run 261 | the function as usual. 262 | 263 | Make sure that everything still works by executing `run` task in Code. 264 | 265 | 266 | ## 10-11. Demo App 267 | 268 | The final demo is a sample application that consists of 5 Azure Functions: 269 | 270 | - **`Landing`** is HTTP GET function which returns an HTML page with a form. User can fill this 271 | form to submit their review of the meetup. The review is then posted to `Send` function. 272 | 273 | - **`Send`** is HTTP POST function that accepts the review text from user's form and puts it 274 | into `poll-item` queue 275 | 276 | - **Twitter** function pulls items from a Storage Queue with twitter-submitted feedback. The 277 | queue is populated by an Azure Logic App which is not part of this repository (there's no code 278 | there, it just listens to a Twitter hashtag). The function then also puts the feedback to 279 | `poll-item` queue 280 | 281 | - **Sentiment** function receives messages from `poll-item` queue, then calls Azure Cognitive 282 | Services to get a sentiment score of the message (from 0.0 to 1.0). It then saves the text 283 | and the score into Table Storage 284 | 285 | - **Result** function reads all the feedback from Table Storage, calculates an average score 286 | and retrieves all the data as JSON 287 | 288 | The inteconnection of these functions is shown on the following chart: 289 | 290 | ![App Function Graph](/10-app/FunctionGraph.png) 291 | 292 | The cool thing about this chart is the fact that it was auto-generated based on `function.json` 293 | files of Azure Functions in `10-app` folder. The tool to generate such chart is in 294 | `tool-function-graph-gen` folder and is based on the [script](https://gist.github.com/mathias-brandewinder/cdd1e0d23bd3047ffe438d48689b2b86) 295 | from [Mathias Brandewinder](http://brandewinder.com/2017/04/01/azure-function-app-diagram/). 296 | The tool generates a text file in GraphViz format, which can be visualized by multiple tools, 297 | e.g. at [WebGraphviz](http://www.webgraphviz.com). 298 | 299 | `11-app-attributes` is the same application, but implemented with attribute-based approach instead of 300 | manually created `function.json` files. It's less work to do manually, but it can't be used 301 | for graph generation directly. 302 | -------------------------------------------------------------------------------- /tool-function-graph-gen/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /tool-function-graph-gen/AssemblyInfo.fs: -------------------------------------------------------------------------------- 1 | namespace AzureFunctionGraphGen.AssemblyInfo 2 | 3 | open System.Reflection 4 | open System.Runtime.CompilerServices 5 | open System.Runtime.InteropServices 6 | 7 | // General Information about an assembly is controlled through the following 8 | // set of attributes. Change these attribute values to modify the information 9 | // associated with an assembly. 10 | [] 11 | [] 12 | [] 13 | [] 14 | [] 15 | [] 16 | [] 17 | [] 18 | 19 | // Setting ComVisible to false makes the types in this assembly not visible 20 | // to COM components. If you need to access a type in this assembly from 21 | // COM, set the ComVisible attribute to true on that type. 22 | [] 23 | 24 | // The following GUID is for the ID of the typelib if this project is exposed to COM 25 | [] 26 | 27 | // Version information for an assembly consists of the following four values: 28 | // 29 | // Major Version 30 | // Minor Version 31 | // Build Number 32 | // Revision 33 | // 34 | // You can specify all the values or you can default the Build and Revision Numbers 35 | // by using the '*' as shown below: 36 | // [] 37 | [] 38 | [] 39 | 40 | do 41 | () -------------------------------------------------------------------------------- /tool-function-graph-gen/AzureFunctionGraphGen.fsproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | 2.0 8 | d78ef308-454e-48b8-889d-2a43fbdf1e89 9 | Exe 10 | AzureFunctionGraphGen 11 | AzureFunctionGraphGen 12 | v4.6.1 13 | true 14 | 4.4.1.0 15 | AzureFunctionGraphGen 16 | 17 | 18 | true 19 | full 20 | false 21 | false 22 | bin\$(Configuration)\ 23 | DEBUG;TRACE 24 | 3 25 | AnyCPU 26 | bin\$(Configuration)\$(AssemblyName).XML 27 | true 28 | 29 | 30 | pdbonly 31 | true 32 | true 33 | bin\$(Configuration)\ 34 | TRACE 35 | 3 36 | AnyCPU 37 | bin\$(Configuration)\$(AssemblyName).XML 38 | true 39 | 40 | 41 | 11 42 | 43 | 44 | 45 | 46 | $(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.0\Framework\v4.0\Microsoft.FSharp.Targets 47 | 48 | 49 | 50 | 51 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\FSharp\Microsoft.FSharp.Targets 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | ..\packages\FSharp.Data.2.4.2\lib\net45\FSharp.Data.dll 65 | 66 | 67 | 68 | FSharp.Core 69 | FSharp.Core.dll 70 | $(MSBuildProgramFiles32)\Reference Assemblies\Microsoft\FSharp\.NETFramework\v4.0\$(TargetFSharpCoreVersion)\FSharp.Core.dll 71 | 72 | 73 | 74 | 75 | 76 | ..\packages\System.ValueTuple.4.3.1\lib\netstandard1.0\System.ValueTuple.dll 77 | 78 | 79 | 80 | 87 | -------------------------------------------------------------------------------- /tool-function-graph-gen/Program.fs: -------------------------------------------------------------------------------- 1 | (* 2 | Reading out bindings 3 | *) 4 | 5 | type Direction = 6 | | Trigger 7 | | In 8 | | Out 9 | 10 | type Properties = Map 11 | 12 | type Binding = { 13 | Argument:string 14 | Direction:Direction 15 | Type:string 16 | Properties:Properties 17 | } 18 | with member this.Value key = this.Properties.TryFind key 19 | 20 | open FSharp.Data 21 | open FSharp.Data.JsonExtensions 22 | 23 | let bindingType (``type``:string, dir:string) = 24 | if ``type``.EndsWith "Trigger" 25 | then 26 | Trigger, ``type``.Replace("Trigger","") 27 | else 28 | if (dir = "in") then In, ``type`` 29 | elif (dir = "out") then Out, ``type`` 30 | else failwith "Unknown binding" 31 | 32 | let extractBindings (contents:string) = 33 | contents 34 | |> JsonValue.Parse 35 | |> fun elements -> elements.GetProperty "bindings" 36 | |> JsonExtensions.AsArray 37 | |> Array.map (fun binding -> 38 | // retrieve the properties we care about 39 | let ``type`` = binding?``type``.AsString() 40 | let direction = if ``type``.EndsWith "Trigger" then "in" else binding?direction.AsString() 41 | let name = binding?name.AsString() 42 | // retrieve the "other" properties 43 | let properties = 44 | binding.Properties 45 | |> Array.filter (fun (key,value) -> 46 | key <> "type" && key <> "name" && key <> "direction" && key <> "methods") 47 | |> Array.map (fun (key,value) -> key, value.AsString()) 48 | |> Map 49 | // detect the direction and type 50 | let direction, ``type`` = bindingType (``type``,direction) 51 | // create and return a binding 52 | { 53 | Type = ``type`` 54 | Direction = direction 55 | Argument = name 56 | Properties = properties 57 | } 58 | ) 59 | 60 | (* 61 | Reading out packages 62 | *) 63 | 64 | type Package = { 65 | Name:string 66 | Version:string 67 | } 68 | 69 | (* 70 | Extracting all the data from a root folder 71 | *) 72 | 73 | open System.IO 74 | 75 | let candidates root = 76 | root 77 | |> Directory.EnumerateDirectories 78 | |> Seq.filter (fun dir -> 79 | Directory.EnumerateFiles(dir) 80 | |> Seq.map FileInfo 81 | |> Seq.exists (fun file -> file.Name = "function.json") 82 | ) 83 | |> Seq.map DirectoryInfo 84 | 85 | type AppGraph = { 86 | Bindings: (string * Binding) [] 87 | } 88 | 89 | let extractGraph (root:string) = 90 | 91 | let functions = candidates root 92 | 93 | let bindings = 94 | functions 95 | |> Seq.map (fun dir -> 96 | let functionName = dir.Name 97 | Path.Combine (dir.FullName,"function.json") 98 | |> File.ReadAllText 99 | |> extractBindings 100 | |> Array.map (fun binding -> 101 | functionName, binding) 102 | ) 103 | |> Seq.collect id 104 | |> Seq.toArray 105 | 106 | { 107 | Bindings = bindings 108 | } 109 | 110 | (* 111 | Rendering the graph 112 | *) 113 | 114 | let quoted (text:string) = sprintf "\"%s\"" text 115 | let indent = " " 116 | 117 | let bindingDescription (functionName: string, binding:Binding) = 118 | match binding.Type with 119 | | "timer" -> "Timer" 120 | | "queue" -> "Queue " + (binding.Properties.["queueName"]) 121 | | "table" -> "Table " + (binding.Properties.["tableName"]) 122 | | "blob" -> "Blob " + (binding.Properties.["path"]) 123 | | "http" -> "HTTP /" + functionName 124 | | _ -> binding.Type 125 | |> quoted 126 | 127 | let packageDescription (package:Package) = 128 | sprintf "%s (%s)" package.Name package.Version 129 | |> quoted 130 | 131 | let functionDescription = quoted 132 | 133 | let renderFunctionNodes format (graph:AppGraph) = 134 | let functionNames = 135 | graph.Bindings 136 | |> Seq.map (fst >> functionDescription) 137 | |> Seq.distinct 138 | Seq.append 139 | [ format ] 140 | functionNames 141 | |> Seq.map (fun name -> indent + name) 142 | |> String.concat "\n" 143 | 144 | let renderBindingNodes format (graph:AppGraph) = 145 | let bindingNames = 146 | graph.Bindings 147 | |> Seq.map bindingDescription 148 | |> Seq.distinct 149 | Seq.append 150 | [ format ] 151 | bindingNames 152 | |> Seq.map (fun name -> indent + name) 153 | |> String.concat "\n" 154 | 155 | let renderTriggers format (graph:AppGraph) = 156 | let triggers = 157 | graph.Bindings 158 | |> Seq.filter (fun (_,binding) -> binding.Direction = Trigger) 159 | |> Seq.map (fun (fn,binding) -> 160 | sprintf "%s -> %s [ label = %s ]" 161 | (bindingDescription (fn, binding)) 162 | (functionDescription fn) 163 | (binding.Argument |> quoted) 164 | ) 165 | |> Seq.distinct 166 | 167 | Seq.append 168 | [ format ] 169 | triggers 170 | |> Seq.map (fun name -> indent + name) 171 | |> String.concat "\n" 172 | 173 | let renderInBindings format (graph:AppGraph) = 174 | let bindings = 175 | graph.Bindings 176 | |> Seq.filter (fun (_,binding) -> binding.Direction = In) 177 | |> Seq.map (fun (fn,binding) -> 178 | sprintf "%s -> %s [ label = %s ]" 179 | (bindingDescription (fn, binding)) 180 | (functionDescription fn) 181 | (binding.Argument |> quoted) 182 | ) 183 | |> Seq.distinct 184 | 185 | Seq.append 186 | [ format ] 187 | bindings 188 | |> Seq.map (fun name -> indent + name) 189 | |> String.concat "\n" 190 | 191 | let renderOutBindings format (graph:AppGraph) = 192 | let bindings = 193 | graph.Bindings 194 | |> Seq.filter (fun (_,binding) -> binding.Direction = Out) 195 | |> Seq.map (fun (fn,binding) -> 196 | sprintf "%s -> %s [ label = %s ]" 197 | (functionDescription fn) 198 | (bindingDescription (fn, binding)) 199 | (binding.Argument |> quoted) 200 | ) 201 | |> Seq.distinct 202 | 203 | Seq.append 204 | [ format ] 205 | bindings 206 | |> Seq.map (fun name -> indent + name) 207 | |> String.concat "\n" 208 | 209 | type GraphFormat = { 210 | FunctionNode:string 211 | BindingNode:string 212 | PackageNode:string 213 | Trigger:string 214 | InBinding:string 215 | OutBinding:string 216 | } 217 | 218 | let graphFormat = { 219 | FunctionNode = "node [shape=doublecircle,style=filled,color=orange]" 220 | BindingNode = "node [shape=box,style=filled,color=yellow]" 221 | PackageNode = "node [shape=box,style=filled,color=lightblue]" 222 | Trigger = "edge [ style=bold ]" 223 | InBinding = "edge [ style=solid ]" 224 | OutBinding = "edge [ style=solid ]" 225 | } 226 | 227 | let renderGraph (format:GraphFormat) (app:AppGraph) = 228 | let functionNodes = renderFunctionNodes format.FunctionNode app 229 | let bindingrNodes = renderBindingNodes format.BindingNode app 230 | let triggers = renderTriggers format.Trigger app 231 | let ins = renderInBindings format.InBinding app 232 | let outs = renderOutBindings format.OutBinding app 233 | 234 | sprintf """digraph app { 235 | %s 236 | %s 237 | %s 238 | %s 239 | %s 240 | }""" functionNodes bindingrNodes triggers ins outs 241 | 242 | 243 | [] 244 | let main argv = 245 | // location on disk 246 | let root = argv.[0]// @"C:\Work\F#unctions\Demos\9-app-m" 247 | 248 | // generate a graphviz file 249 | root 250 | |> extractGraph 251 | |> renderGraph graphFormat 252 | |> fun content -> 253 | File.WriteAllText(argv.[1], content) 254 | 255 | 0 // return an integer exit code 256 | -------------------------------------------------------------------------------- /tool-function-graph-gen/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | --------------------------------------------------------------------------------