├── .github
├── CODE_OF_CONDUCT.md
├── ISSUE_TEMPLATE.md
└── PULL_REQUEST_TEMPLATE.md
├── .gitignore
├── .vscode
├── extensions.json
├── launch.json
├── settings.json
└── tasks.json
├── CHANGELOG.md
├── CONTRIBUTING.md
├── DeleteToDo.cs
├── GetToDo.cs
├── LICENSE.md
├── PatchToDo.cs
├── PostToDo.cs
├── README.md
├── ToDo.cs
├── ToDoModel.cs
├── azure-sql-binding-func-dotnet-todo.csproj
├── default.local.settings.json
├── host.json
├── images
├── testing.png
└── validation.png
├── sql
└── create.sql
└── testing.http
/.github/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Microsoft Open Source Code of Conduct
2 |
3 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
4 |
5 | Resources:
6 |
7 | - [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/)
8 | - [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/)
9 | - Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns
10 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 |
4 | > Please provide us with the following information:
5 | > ---------------------------------------------------------------
6 |
7 | ### This issue is for a: (mark with an `x`)
8 | ```
9 | - [ ] bug report -> please search issues before submitting
10 | - [ ] feature request
11 | - [ ] documentation issue or request
12 | - [ ] regression (a behavior that used to work and stopped in a new release)
13 | ```
14 |
15 | ### Minimal steps to reproduce
16 | >
17 |
18 | ### Any log messages given by the failure
19 | >
20 |
21 | ### Expected/desired behavior
22 | >
23 |
24 | ### OS and Version?
25 | > Windows 7, 8 or 10. Linux (which distribution). macOS (Yosemite? El Capitan? Sierra?)
26 |
27 | ### Versions
28 | >
29 |
30 | ### Mention any other details that might be useful
31 |
32 | > ---------------------------------------------------------------
33 | > Thanks! We'll be in touch soon.
34 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | ## Purpose
2 |
3 | * ...
4 |
5 | ## Does this introduce a breaking change?
6 |
7 | ```
8 | [ ] Yes
9 | [ ] No
10 | ```
11 |
12 | ## Pull Request Type
13 | What kind of change does this Pull Request introduce?
14 |
15 |
16 | ```
17 | [ ] Bugfix
18 | [ ] Feature
19 | [ ] Code style update (formatting, local variables)
20 | [ ] Refactoring (no functional changes, no api changes)
21 | [ ] Documentation content changes
22 | [ ] Other... Please describe:
23 | ```
24 |
25 | ## How to Test
26 | * Get the code
27 |
28 | ```
29 | git clone [repo-address]
30 | cd [repo-name]
31 | git checkout [branch-name]
32 | npm install
33 | ```
34 |
35 | * Test the code
36 |
37 | ```
38 | ```
39 |
40 | ## What to Check
41 | Verify that the following are valid
42 | * ...
43 |
44 | ## Other Information
45 |
--------------------------------------------------------------------------------
/.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 | *.rsuser
8 | *.suo
9 | *.user
10 | *.userosscache
11 | *.sln.docstates
12 |
13 | # User-specific files (MonoDevelop/Xamarin Studio)
14 | *.userprefs
15 |
16 | # Mono auto generated files
17 | mono_crash.*
18 |
19 | # Build results
20 | [Dd]ebug/
21 | [Dd]ebugPublic/
22 | [Rr]elease/
23 | [Rr]eleases/
24 | x64/
25 | x86/
26 | [Aa][Rr][Mm]/
27 | [Aa][Rr][Mm]64/
28 | bld/
29 | [Bb]in/
30 | [Oo]bj/
31 | [Ll]og/
32 | [Ll]ogs/
33 |
34 | # Visual Studio 2015/2017 cache/options directory
35 | .vs/
36 | # Uncomment if you have tasks that create the project's static files in wwwroot
37 | #wwwroot/
38 |
39 | # Visual Studio 2017 auto generated files
40 | Generated\ Files/
41 |
42 | # MSTest test Results
43 | [Tt]est[Rr]esult*/
44 | [Bb]uild[Ll]og.*
45 |
46 | # NUnit
47 | *.VisualState.xml
48 | TestResult.xml
49 | nunit-*.xml
50 |
51 | # Build Results of an ATL Project
52 | [Dd]ebugPS/
53 | [Rr]eleasePS/
54 | dlldata.c
55 |
56 | # Benchmark Results
57 | BenchmarkDotNet.Artifacts/
58 |
59 | # .NET Core
60 | project.lock.json
61 | project.fragment.lock.json
62 | artifacts/
63 |
64 | # StyleCop
65 | StyleCopReport.xml
66 |
67 | # Files built by Visual Studio
68 | *_i.c
69 | *_p.c
70 | *_h.h
71 | *.ilk
72 | *.meta
73 | *.obj
74 | *.iobj
75 | *.pch
76 | *.pdb
77 | *.ipdb
78 | *.pgc
79 | *.pgd
80 | *.rsp
81 | *.sbr
82 | *.tlb
83 | *.tli
84 | *.tlh
85 | *.tmp
86 | *.tmp_proj
87 | *_wpftmp.csproj
88 | *.log
89 | *.vspscc
90 | *.vssscc
91 | .builds
92 | *.pidb
93 | *.svclog
94 | *.scc
95 |
96 | # Chutzpah Test files
97 | _Chutzpah*
98 |
99 | # Visual C++ cache files
100 | ipch/
101 | *.aps
102 | *.ncb
103 | *.opendb
104 | *.opensdf
105 | *.sdf
106 | *.cachefile
107 | *.VC.db
108 | *.VC.VC.opendb
109 |
110 | # Visual Studio profiler
111 | *.psess
112 | *.vsp
113 | *.vspx
114 | *.sap
115 |
116 | # Visual Studio Trace Files
117 | *.e2e
118 |
119 | # TFS 2012 Local Workspace
120 | $tf/
121 |
122 | # Guidance Automation Toolkit
123 | *.gpState
124 |
125 | # ReSharper is a .NET coding add-in
126 | _ReSharper*/
127 | *.[Rr]e[Ss]harper
128 | *.DotSettings.user
129 |
130 | # TeamCity is a build add-in
131 | _TeamCity*
132 |
133 | # DotCover is a Code Coverage Tool
134 | *.dotCover
135 |
136 | # AxoCover is a Code Coverage Tool
137 | .axoCover/*
138 | !.axoCover/settings.json
139 |
140 | # Visual Studio code coverage results
141 | *.coverage
142 | *.coveragexml
143 |
144 | # NCrunch
145 | _NCrunch_*
146 | .*crunch*.local.xml
147 | nCrunchTemp_*
148 |
149 | # MightyMoose
150 | *.mm.*
151 | AutoTest.Net/
152 |
153 | # Web workbench (sass)
154 | .sass-cache/
155 |
156 | # Installshield output folder
157 | [Ee]xpress/
158 |
159 | # DocProject is a documentation generator add-in
160 | DocProject/buildhelp/
161 | DocProject/Help/*.HxT
162 | DocProject/Help/*.HxC
163 | DocProject/Help/*.hhc
164 | DocProject/Help/*.hhk
165 | DocProject/Help/*.hhp
166 | DocProject/Help/Html2
167 | DocProject/Help/html
168 |
169 | # Click-Once directory
170 | publish/
171 |
172 | # Publish Web Output
173 | *.[Pp]ublish.xml
174 | *.azurePubxml
175 | # Note: Comment the next line if you want to checkin your web deploy settings,
176 | # but database connection strings (with potential passwords) will be unencrypted
177 | *.pubxml
178 | *.publishproj
179 |
180 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
181 | # checkin your Azure Web App publish settings, but sensitive information contained
182 | # in these scripts will be unencrypted
183 | PublishScripts/
184 |
185 | # NuGet Packages
186 | *.nupkg
187 | # NuGet Symbol Packages
188 | *.snupkg
189 | # The packages folder can be ignored because of Package Restore
190 | **/[Pp]ackages/*
191 | # except build/, which is used as an MSBuild target.
192 | !**/[Pp]ackages/build/
193 | # Uncomment if necessary however generally it will be regenerated when needed
194 | #!**/[Pp]ackages/repositories.config
195 | # NuGet v3's project.json files produces more ignorable files
196 | *.nuget.props
197 | *.nuget.targets
198 |
199 | # Microsoft Azure Build Output
200 | csx/
201 | *.build.csdef
202 |
203 | # Microsoft Azure Emulator
204 | ecf/
205 | rcf/
206 |
207 | # Windows Store app package directories and files
208 | AppPackages/
209 | BundleArtifacts/
210 | Package.StoreAssociation.xml
211 | _pkginfo.txt
212 | *.appx
213 | *.appxbundle
214 | *.appxupload
215 |
216 | # Visual Studio cache files
217 | # files ending in .cache can be ignored
218 | *.[Cc]ache
219 | # but keep track of directories ending in .cache
220 | !?*.[Cc]ache/
221 |
222 | # Others
223 | ClientBin/
224 | ~$*
225 | *~
226 | *.dbmdl
227 | *.dbproj.schemaview
228 | *.jfm
229 | *.pfx
230 | *.publishsettings
231 | orleans.codegen.cs
232 |
233 | # Including strong name files can present a security risk
234 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
235 | #*.snk
236 |
237 | # Since there are multiple workflows, uncomment next line to ignore bower_components
238 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
239 | #bower_components/
240 |
241 | # RIA/Silverlight projects
242 | Generated_Code/
243 |
244 | # Backup & report files from converting an old project file
245 | # to a newer Visual Studio version. Backup files are not needed,
246 | # because we have git ;-)
247 | _UpgradeReport_Files/
248 | Backup*/
249 | UpgradeLog*.XML
250 | UpgradeLog*.htm
251 | ServiceFabricBackup/
252 | *.rptproj.bak
253 |
254 | # SQL Server files
255 | *.mdf
256 | *.ldf
257 | *.ndf
258 |
259 | # Business Intelligence projects
260 | *.rdl.data
261 | *.bim.layout
262 | *.bim_*.settings
263 | *.rptproj.rsuser
264 | *- [Bb]ackup.rdl
265 | *- [Bb]ackup ([0-9]).rdl
266 | *- [Bb]ackup ([0-9][0-9]).rdl
267 |
268 | # Microsoft Fakes
269 | FakesAssemblies/
270 |
271 | # GhostDoc plugin setting file
272 | *.GhostDoc.xml
273 |
274 | # Node.js Tools for Visual Studio
275 | .ntvs_analysis.dat
276 | node_modules/
277 |
278 | # Visual Studio 6 build log
279 | *.plg
280 |
281 | # Visual Studio 6 workspace options file
282 | *.opt
283 |
284 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
285 | *.vbw
286 |
287 | # Visual Studio LightSwitch build output
288 | **/*.HTMLClient/GeneratedArtifacts
289 | **/*.DesktopClient/GeneratedArtifacts
290 | **/*.DesktopClient/ModelManifest.xml
291 | **/*.Server/GeneratedArtifacts
292 | **/*.Server/ModelManifest.xml
293 | _Pvt_Extensions
294 |
295 | # Paket dependency manager
296 | .paket/paket.exe
297 | paket-files/
298 |
299 | # FAKE - F# Make
300 | .fake/
301 |
302 | # CodeRush personal settings
303 | .cr/personal
304 |
305 | # Python Tools for Visual Studio (PTVS)
306 | __pycache__/
307 | *.pyc
308 |
309 | # Cake - Uncomment if you are using it
310 | # tools/**
311 | # !tools/packages.config
312 |
313 | # Tabs Studio
314 | *.tss
315 |
316 | # Telerik's JustMock configuration file
317 | *.jmconfig
318 |
319 | # BizTalk build output
320 | *.btp.cs
321 | *.btm.cs
322 | *.odx.cs
323 | *.xsd.cs
324 |
325 | # OpenCover UI analysis results
326 | OpenCover/
327 |
328 | # Azure Stream Analytics local run output
329 | ASALocalRun/
330 |
331 | # MSBuild Binary and Structured Log
332 | *.binlog
333 |
334 | # NVidia Nsight GPU debugger configuration file
335 | *.nvuser
336 |
337 | # MFractors (Xamarin productivity tool) working folder
338 | .mfractor/
339 |
340 | # Local History for Visual Studio
341 | .localhistory/
342 |
343 | # BeatPulse healthcheck temp database
344 | healthchecksdb
345 |
346 | # Backup folder for Package Reference Convert tool in Visual Studio 2017
347 | MigrationBackup/
348 |
349 | # Ionide (cross platform F# VS Code tools) working folder
350 | .ionide/
351 |
352 |
353 | local.settings.json
354 | *.log
--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | "recommendations": [
3 | "ms-azuretools.vscode-azurefunctions",
4 | "ms-dotnettools.csharp",
5 | "ms-mssql.mssql",
6 | "humao.rest-client"
7 | ]
8 | }
9 |
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "0.2.0",
3 | "configurations": [
4 | {
5 | "name": "Attach to .NET Functions",
6 | "type": "coreclr",
7 | "request": "attach",
8 | "processId": "${command:azureFunctions.pickProcess}"
9 | }
10 | ]
11 | }
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "azureFunctions.deploySubpath": "bin/Release/net6.0/publish",
3 | "azureFunctions.projectLanguage": "C#",
4 | "azureFunctions.projectRuntime": "~4",
5 | "debug.internalConsoleOptions": "neverOpen",
6 | "azureFunctions.preDeployTask": "publish (functions)"
7 | }
--------------------------------------------------------------------------------
/.vscode/tasks.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "2.0.0",
3 | "tasks": [
4 | {
5 | "label": "clean (functions)",
6 | "command": "dotnet",
7 | "args": [
8 | "clean",
9 | "/property:GenerateFullPaths=true",
10 | "/consoleloggerparameters:NoSummary"
11 | ],
12 | "type": "process",
13 | "problemMatcher": "$msCompile"
14 | },
15 | {
16 | "label": "build (functions)",
17 | "command": "dotnet",
18 | "args": [
19 | "build",
20 | "/property:GenerateFullPaths=true",
21 | "/consoleloggerparameters:NoSummary"
22 | ],
23 | "type": "process",
24 | "dependsOn": "clean (functions)",
25 | "group": {
26 | "kind": "build",
27 | "isDefault": true
28 | },
29 | "problemMatcher": "$msCompile"
30 | },
31 | {
32 | "label": "clean release (functions)",
33 | "command": "dotnet",
34 | "args": [
35 | "clean",
36 | "--configuration",
37 | "Release",
38 | "/property:GenerateFullPaths=true",
39 | "/consoleloggerparameters:NoSummary"
40 | ],
41 | "type": "process",
42 | "problemMatcher": "$msCompile"
43 | },
44 | {
45 | "label": "publish (functions)",
46 | "command": "dotnet",
47 | "args": [
48 | "publish",
49 | "--configuration",
50 | "Release",
51 | "/property:GenerateFullPaths=true",
52 | "/consoleloggerparameters:NoSummary"
53 | ],
54 | "type": "process",
55 | "dependsOn": "clean release (functions)",
56 | "problemMatcher": "$msCompile"
57 | },
58 | {
59 | "type": "func",
60 | "dependsOn": "build (functions)",
61 | "options": {
62 | "cwd": "${workspaceFolder}/bin/Debug/net6.0"
63 | },
64 | "command": "host start",
65 | "isBackground": true,
66 | "problemMatcher": "$func-dotnet-watch"
67 | }
68 | ]
69 | }
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ## [project-title] Changelog
2 |
3 |
4 | # x.y.z (yyyy-mm-dd)
5 |
6 | *Features*
7 | * ...
8 |
9 | *Bug Fixes*
10 | * ...
11 |
12 | *Breaking Changes*
13 | * ...
14 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing to [project-title]
2 |
3 | This project welcomes contributions and suggestions. Most contributions require you to agree to a
4 | Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us
5 | the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com.
6 |
7 | When you submit a pull request, a CLA bot will automatically determine whether you need to provide
8 | a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions
9 | provided by the bot. You will only need to do this once across all repos using our CLA.
10 |
11 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
12 | For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or
13 | contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
14 |
15 | - [Code of Conduct](#coc)
16 | - [Issues and Bugs](#issue)
17 | - [Feature Requests](#feature)
18 | - [Submission Guidelines](#submit)
19 |
20 | ## Code of Conduct
21 | Help us keep this project open and inclusive. Please read and follow our [Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
22 |
23 | ## Found an Issue?
24 | If you find a bug in the source code or a mistake in the documentation, you can help us by
25 | [submitting an issue](#submit-issue) to the GitHub Repository. Even better, you can
26 | [submit a Pull Request](#submit-pr) with a fix.
27 |
28 | ## Want a Feature?
29 | You can *request* a new feature by [submitting an issue](#submit-issue) to the GitHub
30 | Repository. If you would like to *implement* a new feature, please submit an issue with
31 | a proposal for your work first, to be sure that we can use it.
32 |
33 | * **Small Features** can be crafted and directly [submitted as a Pull Request](#submit-pr).
34 |
35 | ## Submission Guidelines
36 |
37 | ### Submitting an Issue
38 | Before you submit an issue, search the archive, maybe your question was already answered.
39 |
40 | If your issue appears to be a bug, and hasn't been reported, open a new issue.
41 | Help us to maximize the effort we can spend fixing issues and adding new
42 | features, by not reporting duplicate issues. Providing the following information will increase the
43 | chances of your issue being dealt with quickly:
44 |
45 | * **Overview of the Issue** - if an error is being thrown a non-minified stack trace helps
46 | * **Version** - what version is affected (e.g. 0.1.2)
47 | * **Motivation for or Use Case** - explain what are you trying to do and why the current behavior is a bug for you
48 | * **Browsers and Operating System** - is this a problem with all browsers?
49 | * **Reproduce the Error** - provide a live example or a unambiguous set of steps
50 | * **Related Issues** - has a similar issue been reported before?
51 | * **Suggest a Fix** - if you can't fix the bug yourself, perhaps you can point to what might be
52 | causing the problem (line of code or commit)
53 |
54 | You can file new issues by providing the above information at the corresponding repository's issues link: https://github.com/[organization-name]/[repository-name]/issues/new].
55 |
56 | ### Submitting a Pull Request (PR)
57 | Before you submit your Pull Request (PR) consider the following guidelines:
58 |
59 | * Search the repository (https://github.com/[organization-name]/[repository-name]/pulls) for an open or closed PR
60 | that relates to your submission. You don't want to duplicate effort.
61 |
62 | * Make your changes in a new git fork:
63 |
64 | * Commit your changes using a descriptive commit message
65 | * Push your fork to GitHub:
66 | * In GitHub, create a pull request
67 | * If we suggest changes then:
68 | * Make the required updates.
69 | * Rebase your fork and force push to your GitHub repository (this will update your Pull Request):
70 |
71 | ```shell
72 | git rebase master -i
73 | git push -f
74 | ```
75 |
76 | That's it! Thank you for your contribution!
77 |
--------------------------------------------------------------------------------
/DeleteToDo.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation. All rights reserved.
2 | // Licensed under the MIT License. See LICENSE.md in the project root for license information.
3 |
4 | using System;
5 | using System.Collections.Generic;
6 | using Microsoft.AspNetCore.Mvc;
7 | using Microsoft.Azure.WebJobs;
8 | using Microsoft.Azure.WebJobs.Extensions.Http;
9 | using Microsoft.AspNetCore.Http;
10 | using Microsoft.Extensions.Logging;
11 |
12 | namespace AzureSQL.ToDo
13 | {
14 | public static class DeleteToDo
15 | {
16 | // delete all items or a specific item from querystring
17 | // returns remaining items
18 | // uses input binding with a stored procedure DeleteToDo to delete items and return remaining items
19 | [FunctionName("DeleteToDo")]
20 | public static IActionResult Run(
21 | [HttpTrigger(AuthorizationLevel.Anonymous, "delete", Route = "DeleteFunction")] HttpRequest req,
22 | ILogger log,
23 | [Sql(commandText: "DeleteToDo", commandType: System.Data.CommandType.StoredProcedure,
24 | parameters: "@Id={Query.id}", connectionStringSetting: "SqlConnectionString")]
25 | IEnumerable toDoItems)
26 | {
27 | return new OkObjectResult(toDoItems);
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/GetToDo.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation. All rights reserved.
2 | // Licensed under the MIT License. See LICENSE.md in the project root for license information.
3 |
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Threading.Tasks;
7 | using Microsoft.AspNetCore.Http;
8 | using Microsoft.AspNetCore.Mvc;
9 | using Microsoft.Azure.WebJobs;
10 | using Microsoft.Azure.WebJobs.Extensions.Http;
11 | using Microsoft.Extensions.Logging;
12 |
13 | namespace AzureSQL.ToDo
14 | {
15 | public static class GetToDos
16 | {
17 | // return items from ToDo table
18 | // id querystring in the query text to filter if specified
19 | // uses input binding to run the query and return the results
20 | [FunctionName("GetToDos")]
21 | public static async Task Run(
22 | [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "GetFunction")] HttpRequest req,
23 | ILogger log,
24 | [Sql(commandText: "if @Id = '' select Id, [order], title, url, completed from dbo.ToDo else select Id, [order], title, url, completed from dbo.ToDo where @Id = Id", connectionStringSetting: "SqlConnectionString", commandType: System.Data.CommandType.Text, parameters: "@Id={Query.id}")] IAsyncEnumerable toDos)
25 | {
26 | return new OkObjectResult(toDos);
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) Microsoft Corporation.
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
--------------------------------------------------------------------------------
/PatchToDo.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation. All rights reserved.
2 | // Licensed under the MIT License. See LICENSE.md in the project root for license information.
3 |
4 | using System;
5 | using System.IO;
6 | using System.Collections.Generic;
7 | using System.Threading.Tasks;
8 | using Microsoft.AspNetCore.Http;
9 | using Microsoft.AspNetCore.Mvc;
10 | using Microsoft.Azure.WebJobs;
11 | using Microsoft.Azure.WebJobs.Extensions.Http;
12 | using Microsoft.Extensions.Logging;
13 | using Newtonsoft.Json;
14 |
15 | namespace AzureSQL.ToDo
16 | {
17 | public static class PatchToDo
18 | {
19 | // update an item from new data in body object
20 | // receives a list in the body with the existing data in at first position, and updates in at second position
21 | // uses output binding to update the row in ToDo table
22 | [FunctionName("PatchToDo")]
23 | public static async Task Run(
24 | [HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "PatchFunction")] HttpRequest req,
25 | ILogger log,
26 | [Sql(commandText: "dbo.ToDo", connectionStringSetting: "SqlConnectionString")] IAsyncCollector toDoItems)
27 | {
28 | string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
29 | List incomingToDoItems = JsonConvert.DeserializeObject>(requestBody);
30 |
31 | // existing at first position, new at second position
32 | ToDoItem toDoItem = incomingToDoItems[0];
33 | ToDoItem newToDoItem = incomingToDoItems[1];
34 |
35 | // compare the two items attributes
36 | if (newToDoItem.title != null)
37 | {
38 | toDoItem.title = newToDoItem.title;
39 | }
40 | if (newToDoItem.order != null)
41 | {
42 | toDoItem.order = newToDoItem.order;
43 | }
44 | if (newToDoItem.completed != null)
45 | {
46 | toDoItem.completed = newToDoItem.completed;
47 | }
48 |
49 | await toDoItems.AddAsync(toDoItem);
50 | await toDoItems.FlushAsync();
51 |
52 | return new OkObjectResult(toDoItem);
53 |
54 | }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/PostToDo.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation. All rights reserved.
2 | // Licensed under the MIT License. See LICENSE.md in the project root for license information.
3 |
4 | using System;
5 | using System.Collections.Generic;
6 | using System.IO;
7 | using System.Threading.Tasks;
8 | using Microsoft.AspNetCore.Http;
9 | using Microsoft.AspNetCore.Mvc;
10 | using Microsoft.Azure.WebJobs;
11 | using Microsoft.Azure.WebJobs.Extensions.Http;
12 | using Microsoft.Extensions.Logging;
13 | using Newtonsoft.Json;
14 |
15 | namespace AzureSQL.ToDo
16 | {
17 | public static class PostToDo
18 | {
19 | // create a new ToDoItem from body object
20 | // uses output binding to insert new item into ToDo table
21 | [FunctionName("PostToDo")]
22 | public static async Task Run(
23 | [HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "PostFunction")] HttpRequest req,
24 | ILogger log,
25 | [Sql(commandText: "dbo.ToDo", connectionStringSetting: "SqlConnectionString")] IAsyncCollector toDoItems)
26 | {
27 | string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
28 | ToDoItem toDoItem = JsonConvert.DeserializeObject(requestBody);
29 |
30 | // generate a new id for the todo item
31 | toDoItem.Id = Guid.NewGuid();
32 |
33 | // set Url from env variable ToDoUri
34 | toDoItem.url = Environment.GetEnvironmentVariable("ToDoUri")+"?id="+toDoItem.Id.ToString();
35 |
36 | // if completed is not provided, default to false
37 | if (toDoItem.completed == null)
38 | {
39 | toDoItem.completed = false;
40 | }
41 |
42 | await toDoItems.AddAsync(toDoItem);
43 | await toDoItems.FlushAsync();
44 | List toDoItemList = new List { toDoItem };
45 |
46 | return new OkObjectResult(toDoItemList);
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | page_type: sample
3 | languages:
4 | - csharp
5 | - sql
6 | - tsql
7 | products:
8 | - azure-functions
9 | - azure-sql-database
10 | - sql-server
11 | - azure-sql-managed-instance
12 | - azure-sqlserver-vm
13 | - dotnet
14 | name: ToDo API backend with Azure SQL bindings
15 | description: Implement the ToDo Backend in .NET with Azure SQL bindings for Azure Functions
16 | urlFragment: todo-backend-dotnet-azure-sql-bindings-azure-functions
17 | ---
18 |
19 | # ToDo Backend Implementation in .NET with Azure SQL bindings for Azure Functions
20 |
21 | 
22 |
23 | This project implements the [Todo Backend API](http://www.todobackend.com/index.html) using Azure Functions (.NET) and Azure SQL through HTTP triggers and Azure SQL input/output bindings.
24 |
25 | ## ToDo Backend
26 |
27 | This project implements a ToDo endpoint with the following actions:
28 |
29 | * GET all ToDos
30 | * GET a ToDo by Id
31 | * POST a new ToDo
32 | * PATCH an update to a ToDo
33 | * DELETE a ToDo by Id
34 | * DELETE all ToDos
35 |
36 |
37 | ## Getting Started
38 |
39 | ### Quickstart
40 |
41 | 1. Configure your development environment for creating Azure Functions with .NET. This [VS Code example](https://docs.microsoft.com/azure/azure-functions/create-first-function-vs-code-csharp?tabs=in-process#configure-your-environment) includes the .NET SDK, Azure Functions Core Tools, and the C# and Azure Functions extensions for VS Code.
42 | 2. Clone the repository to your environment
43 | 3. Create an [Azure SQL Database](https://docs.microsoft.com/azure/azure-sql/database/single-database-create-quickstart) and execute the script in [/sql/create.sql](/sql/create.sql) to create the table and stored procedure used by this example. Optionally the local development can be done against an local database, such as in a [Docker container](https://docs.microsoft.com/sql/linux/sql-server-linux-docker-container-deployment).
44 |
45 |
46 | ### Application Settings
47 |
48 | This example uses 2 application settings to control either secret or deployment-specific information. During local development, these values are stored in `local.settings.json` at the project root.
49 |
50 | * **Connection string to SQL database (General format)** "SqlConnectionString": "Server=tcp:SERVERNAME,PORT;Initial Catalog=DATABASENAME;Persist Security Info=False;User ID=USERNAME;Password=USERPASSWORD;"
51 | * **Primary endpoint URL** "ToDoUri": "http://localhost:7071/api/ToDo"
52 |
53 |
54 | ### Testing
55 | Using the [REST Client](https://marketplace.visualstudio.com/items?itemName=humao.rest-client) extension for VS Code, the [testing.http](testing.http) file provides example requests for the functionality.
56 |
57 |
58 | 
59 |
60 | ## Demo/Validation
61 |
62 | The ToDo backend specification has an accompanying runner for tests that validate the functionality. To run these tests on the demo endpoint, go to [http://todobackend.com/specs/index.html?https://azuresqltodo.azurewebsites.net/api/ToDo](http://todobackend.com/specs/index.html?https://azuresqltodo.azurewebsites.net/api/ToDo).
63 |
64 | The functions runtime and SQL database may have gone idle when you test the link, if you find tests fail retry after a few seconds.
65 |
66 | 
67 |
68 | ## Resources
69 |
70 |
71 | - [Azure SQL binding for Azure Functions docs](https://docs.microsoft.com/azure/azure-functions/functions-bindings-azure-sql)
72 | - [Azure SQL binding for Azure Functions code and samples](https://github.com/Azure/azure-functions-sql-extension)
73 |
--------------------------------------------------------------------------------
/ToDo.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation. All rights reserved.
2 | // Licensed under the MIT License. See LICENSE.md in the project root for license information.
3 |
4 | using System;
5 | using System.Collections.Generic;
6 | using System.IO;
7 | using System.Net.Http;
8 | using System.Net.Http.Json;
9 | using System.Threading.Tasks;
10 | using Microsoft.AspNetCore.Mvc;
11 | using Microsoft.Azure.WebJobs;
12 | using Microsoft.Azure.WebJobs.Extensions.Http;
13 | using Microsoft.AspNetCore.Http;
14 | using Microsoft.Extensions.Logging;
15 | using Newtonsoft.Json;
16 |
17 | namespace AzureSQL.ToDo
18 | {
19 | public static class ToDo
20 | {
21 | // primary endpoint for the ToDo API
22 | // all other functions are dependencies from this function
23 | [FunctionName("ToDo")]
24 | public static async Task Run(
25 | [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", "patch", "delete", Route = null)] HttpRequest req,
26 | ILogger log)
27 | {
28 | // verify the id querystring is a Guid type
29 | string QId = req.Query["id"];
30 | Guid GId = Guid.Empty;
31 | if (!Guid.TryParse(QId, out GId) && !string.IsNullOrEmpty(QId))
32 | {
33 | return new BadRequestObjectResult($"Invalid id: {QId}");
34 | }
35 |
36 | // parse the request body
37 | string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
38 | var bodyObject = JsonConvert.DeserializeObject(requestBody);
39 |
40 | log.LogInformation("ToDo API");
41 | log.LogInformation("Request Body: " + requestBody);
42 | log.LogInformation("Method: " + req.Method);
43 |
44 | List toDoResponseList = new List();
45 | using (HttpClient client = new HttpClient()) {
46 | // get uri from app settings
47 | client.BaseAddress = new Uri(Environment.GetEnvironmentVariable("ToDoUri"));
48 | // setup the request query parameter for item id
49 | string queryParams = "?id=" + (QId ?? "");
50 |
51 | // switch based on request method, pass query param and/or body object to the corresponding function
52 | switch (req.Method)
53 | {
54 | case "GET":
55 | var getResponse = await client.GetAsync("GetFunction"+queryParams);
56 |
57 | // return a list of ToDoItems if no querystring
58 | if (string.IsNullOrEmpty(QId))
59 | {
60 | toDoResponseList = JsonConvert.DeserializeObject>(await getResponse.Content.ReadAsStringAsync());
61 | return new OkObjectResult(toDoResponseList);
62 | }
63 | // return a single ToDoItem if querystring
64 | else
65 | {
66 | toDoResponseList = JsonConvert.DeserializeObject>(await getResponse.Content.ReadAsStringAsync());
67 | if (toDoResponseList.Count > 0)
68 | {
69 | // return the first item in the list (should be only item)
70 | return new OkObjectResult(toDoResponseList[0]);
71 | } else {
72 | // return a 404 for no item found
73 | return new NotFoundObjectResult(toDoResponseList);
74 | }
75 | }
76 | case "POST":
77 | // create a new ToDoItem from body object
78 | var postResponse = await client.PostAsJsonAsync("PostFunction"+queryParams, bodyObject);
79 | toDoResponseList = JsonConvert.DeserializeObject>(await postResponse.Content.ReadAsStringAsync());
80 | return new OkObjectResult(toDoResponseList[0]);
81 |
82 | case "PATCH":
83 | // update an item from new data in body object
84 | // need both the existing data and the new data to update
85 | // create a list and put the existing data in at first position
86 | var getExistingResponse = await client.GetAsync("GetFunction"+queryParams);
87 | List toDoPatchList = JsonConvert.DeserializeObject>(await getExistingResponse.Content.ReadAsStringAsync());
88 |
89 | // put the patch body in at second position
90 | toDoPatchList.Add(JsonConvert.DeserializeObject(requestBody));
91 |
92 | // call patch endpoint with list of existing and new data
93 | var patchResponse = await client.PostAsJsonAsync("PatchFunction"+queryParams, toDoPatchList);
94 | toDoResponseList.Add(JsonConvert.DeserializeObject(await patchResponse.Content.ReadAsStringAsync()));
95 | return new OkObjectResult(toDoResponseList[0]);
96 |
97 | case "DELETE":
98 | // delete all items or a specific item from querystring
99 | // returns remaining items
100 | var deleteResponse = await client.DeleteAsync("DeleteFunction"+queryParams);
101 | toDoResponseList = JsonConvert.DeserializeObject>(await deleteResponse.Content.ReadAsStringAsync());
102 | return new OkObjectResult(toDoResponseList);
103 | default:
104 | //do nothing
105 | break;
106 | }
107 | }
108 |
109 | // return badrequest
110 | return new BadRequestObjectResult("Bad Request");
111 | }
112 | }
113 | }
114 |
--------------------------------------------------------------------------------
/ToDoModel.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation. All rights reserved.
2 | // Licensed under the MIT License. See LICENSE.md in the project root for license information.
3 |
4 | using System;
5 |
6 | namespace AzureSQL.ToDo
7 | {
8 | public class ToDoItem
9 | {
10 | public Guid Id { get; set; }
11 | public int? order { get; set; }
12 | public string title { get; set; }
13 | public string url { get; set; }
14 | public bool? completed { get; set; }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/azure-sql-binding-func-dotnet-todo.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | net6.0
4 | v4
5 | azure_sql_binding_func_dotnet_todo
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | PreserveNewest
14 |
15 |
16 | PreserveNewest
17 | Never
18 |
19 |
20 |
--------------------------------------------------------------------------------
/default.local.settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "IsEncrypted": false,
3 | "Values": {
4 | "AzureWebJobsStorage": "",
5 | "FUNCTIONS_WORKER_RUNTIME": "dotnet",
6 | "SqlConnectionString": "Server={SERVERNAME};Initial Catalog={DATABASENAME};Persist Security Info=False;User ID={USERNAME};Password={PASSWORD};",
7 | "ToDoUri": "http://localhost:7071/api/ToDo"
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/host.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "2.0",
3 | "logging": {
4 | "applicationInsights": {
5 | "samplingSettings": {
6 | "isEnabled": true,
7 | "excludedTypes": "Request"
8 | }
9 | }
10 | }
11 | }
--------------------------------------------------------------------------------
/images/testing.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Azure-Samples/azure-sql-binding-func-dotnet-todo/6cad5f58ddfd76208d6865ff52dc1eb2c13e5385/images/testing.png
--------------------------------------------------------------------------------
/images/validation.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Azure-Samples/azure-sql-binding-func-dotnet-todo/6cad5f58ddfd76208d6865ff52dc1eb2c13e5385/images/validation.png
--------------------------------------------------------------------------------
/sql/create.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE dbo.ToDo (
2 | [Id] UNIQUEIDENTIFIER PRIMARY KEY,
3 | [order] INT NULL,
4 | [title] NVARCHAR(200) NOT NULL,
5 | [url] NVARCHAR(200) NOT NULL,
6 | [completed] BIT NOT NULL
7 | );
8 | GO
9 |
10 |
11 | CREATE PROCEDURE [dbo].[DeleteToDo]
12 | @Id NVARCHAR(100)
13 | AS
14 | DECLARE @UID UNIQUEIDENTIFIER = TRY_CAST(@ID AS UNIQUEIDENTIFIER)
15 | IF @UId IS NOT NULL AND @Id != ''
16 | BEGIN
17 | DELETE FROM dbo.ToDo WHERE Id = @UID
18 | END
19 | ELSE
20 | BEGIN
21 | DELETE FROM dbo.ToDo WHERE @ID = ''
22 | END
23 |
24 | SELECT [Id], [order], [title], [url], [completed] FROM dbo.ToDo
25 | GO
26 |
--------------------------------------------------------------------------------
/testing.http:
--------------------------------------------------------------------------------
1 | // retrieves all todo items from database
2 | GET http://localhost:7071/api/ToDo?id= HTTP/1.1
3 |
4 | ###
5 | // retrieves a specific todo item from database
6 | GET http://localhost:7071/api/ToDo?id=98230fc4-2ce7-4b1f-aad1-dabaf372b76f HTTP/1.1
7 |
8 | ###
9 | // retrieves an invalid todo item from database
10 | GET http://localhost:7071/api/ToDo?id=gdfsgsf HTTP/1.1
11 |
12 | ###
13 | // adds a new todo to the database
14 | POST http://localhost:7071/api/ToDo HTTP/1.1
15 | Content-Type: application/json
16 |
17 | {"title":"test this sample"}
18 |
19 | ###
20 | // updates a specific todo item from database
21 | PATCH http://localhost:7071/api/ToDo?id=94319c5c-4a11-47f0-a38b-45dc4807c8bd HTTP/1.1
22 | Content-Type: application/json
23 |
24 | {"title":"walk the dog"}
25 |
26 | ###
27 | // deletes a specific todo item from database
28 | DELETE http://localhost:7071/api/ToDo?id=98230fc4-2ce7-4b1f-aad1-dabaf372b76f HTTP/1.1
29 |
30 | ###
31 | // deletes all todo items from database
32 | DELETE http://localhost:7071/api/ToDo?id= HTTP/1.1
33 |
--------------------------------------------------------------------------------