├── .github
├── ISSUE_TEMPLATE.md
└── PULL_REQUEST_TEMPLATE.md
├── .gitignore
├── CHANGELOG.md
├── CONTRIBUTING.md
├── CosmosTableSamples.sln
├── CosmosTableSamples
├── AdvancedSamples.cs
├── AppSettings.cs
├── BasicSamples.cs
├── Common.cs
├── CosmosTableSamples.csproj
├── Model
│ └── CustomerEntity.cs
├── Program.cs
├── SamplesUtils.cs
└── Settings.json
├── LICENSE.md
└── README.md
/.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 | *.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/2017 cache/options directory
28 | .vs/
29 | # Uncomment if you have tasks that create the project's static files in wwwroot
30 | #wwwroot/
31 |
32 | # Visual Studio 2017 auto generated files
33 | Generated\ Files/
34 |
35 | # MSTest test Results
36 | [Tt]est[Rr]esult*/
37 | [Bb]uild[Ll]og.*
38 |
39 | # NUNIT
40 | *.VisualState.xml
41 | TestResult.xml
42 |
43 | # Build Results of an ATL Project
44 | [Dd]ebugPS/
45 | [Rr]eleasePS/
46 | dlldata.c
47 |
48 | # Benchmark Results
49 | BenchmarkDotNet.Artifacts/
50 |
51 | # .NET Core
52 | project.lock.json
53 | project.fragment.lock.json
54 | artifacts/
55 | **/Properties/launchSettings.json
56 |
57 | # StyleCop
58 | StyleCopReport.xml
59 |
60 | # Files built by Visual Studio
61 | *_i.c
62 | *_p.c
63 | *_i.h
64 | *.ilk
65 | *.meta
66 | *.obj
67 | *.iobj
68 | *.pch
69 | *.pdb
70 | *.ipdb
71 | *.pgc
72 | *.pgd
73 | *.rsp
74 | *.sbr
75 | *.tlb
76 | *.tli
77 | *.tlh
78 | *.tmp
79 | *.tmp_proj
80 | *.log
81 | *.vspscc
82 | *.vssscc
83 | .builds
84 | *.pidb
85 | *.svclog
86 | *.scc
87 |
88 | # Chutzpah Test files
89 | _Chutzpah*
90 |
91 | # Visual C++ cache files
92 | ipch/
93 | *.aps
94 | *.ncb
95 | *.opendb
96 | *.opensdf
97 | *.sdf
98 | *.cachefile
99 | *.VC.db
100 | *.VC.VC.opendb
101 |
102 | # Visual Studio profiler
103 | *.psess
104 | *.vsp
105 | *.vspx
106 | *.sap
107 |
108 | # Visual Studio Trace Files
109 | *.e2e
110 |
111 | # TFS 2012 Local Workspace
112 | $tf/
113 |
114 | # Guidance Automation Toolkit
115 | *.gpState
116 |
117 | # ReSharper is a .NET coding add-in
118 | _ReSharper*/
119 | *.[Rr]e[Ss]harper
120 | *.DotSettings.user
121 |
122 | # JustCode is a .NET coding add-in
123 | .JustCode
124 |
125 | # TeamCity is a build add-in
126 | _TeamCity*
127 |
128 | # DotCover is a Code Coverage Tool
129 | *.dotCover
130 |
131 | # AxoCover is a Code Coverage Tool
132 | .axoCover/*
133 | !.axoCover/settings.json
134 |
135 | # Visual Studio code coverage results
136 | *.coverage
137 | *.coveragexml
138 |
139 | # NCrunch
140 | _NCrunch_*
141 | .*crunch*.local.xml
142 | nCrunchTemp_*
143 |
144 | # MightyMoose
145 | *.mm.*
146 | AutoTest.Net/
147 |
148 | # Web workbench (sass)
149 | .sass-cache/
150 |
151 | # Installshield output folder
152 | [Ee]xpress/
153 |
154 | # DocProject is a documentation generator add-in
155 | DocProject/buildhelp/
156 | DocProject/Help/*.HxT
157 | DocProject/Help/*.HxC
158 | DocProject/Help/*.hhc
159 | DocProject/Help/*.hhk
160 | DocProject/Help/*.hhp
161 | DocProject/Help/Html2
162 | DocProject/Help/html
163 |
164 | # Click-Once directory
165 | publish/
166 |
167 | # Publish Web Output
168 | *.[Pp]ublish.xml
169 | *.azurePubxml
170 | # Note: Comment the next line if you want to checkin your web deploy settings,
171 | # but database connection strings (with potential passwords) will be unencrypted
172 | *.pubxml
173 | *.publishproj
174 |
175 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
176 | # checkin your Azure Web App publish settings, but sensitive information contained
177 | # in these scripts will be unencrypted
178 | PublishScripts/
179 |
180 | # NuGet Packages
181 | *.nupkg
182 | # The packages folder can be ignored because of Package Restore
183 | **/[Pp]ackages/*
184 | # except build/, which is used as an MSBuild target.
185 | !**/[Pp]ackages/build/
186 | # Uncomment if necessary however generally it will be regenerated when needed
187 | #!**/[Pp]ackages/repositories.config
188 | # NuGet v3's project.json files produces more ignorable files
189 | *.nuget.props
190 | *.nuget.targets
191 |
192 | # Microsoft Azure Build Output
193 | csx/
194 | *.build.csdef
195 |
196 | # Microsoft Azure Emulator
197 | ecf/
198 | rcf/
199 |
200 | # Windows Store app package directories and files
201 | AppPackages/
202 | BundleArtifacts/
203 | Package.StoreAssociation.xml
204 | _pkginfo.txt
205 | *.appx
206 |
207 | # Visual Studio cache files
208 | # files ending in .cache can be ignored
209 | *.[Cc]ache
210 | # but keep track of directories ending in .cache
211 | !*.[Cc]ache/
212 |
213 | # Others
214 | ClientBin/
215 | ~$*
216 | *~
217 | *.dbmdl
218 | *.dbproj.schemaview
219 | *.jfm
220 | *.pfx
221 | *.publishsettings
222 | orleans.codegen.cs
223 |
224 | # Including strong name files can present a security risk
225 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
226 | #*.snk
227 |
228 | # Since there are multiple workflows, uncomment next line to ignore bower_components
229 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
230 | #bower_components/
231 |
232 | # RIA/Silverlight projects
233 | Generated_Code/
234 |
235 | # Backup & report files from converting an old project file
236 | # to a newer Visual Studio version. Backup files are not needed,
237 | # because we have git ;-)
238 | _UpgradeReport_Files/
239 | Backup*/
240 | UpgradeLog*.XML
241 | UpgradeLog*.htm
242 | ServiceFabricBackup/
243 | *.rptproj.bak
244 |
245 | # SQL Server files
246 | *.mdf
247 | *.ldf
248 | *.ndf
249 |
250 | # Business Intelligence projects
251 | *.rdl.data
252 | *.bim.layout
253 | *.bim_*.settings
254 | *.rptproj.rsuser
255 |
256 | # Microsoft Fakes
257 | FakesAssemblies/
258 |
259 | # GhostDoc plugin setting file
260 | *.GhostDoc.xml
261 |
262 | # Node.js Tools for Visual Studio
263 | .ntvs_analysis.dat
264 | node_modules/
265 |
266 | # Visual Studio 6 build log
267 | *.plg
268 |
269 | # Visual Studio 6 workspace options file
270 | *.opt
271 |
272 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
273 | *.vbw
274 |
275 | # Visual Studio LightSwitch build output
276 | **/*.HTMLClient/GeneratedArtifacts
277 | **/*.DesktopClient/GeneratedArtifacts
278 | **/*.DesktopClient/ModelManifest.xml
279 | **/*.Server/GeneratedArtifacts
280 | **/*.Server/ModelManifest.xml
281 | _Pvt_Extensions
282 |
283 | # Paket dependency manager
284 | .paket/paket.exe
285 | paket-files/
286 |
287 | # FAKE - F# Make
288 | .fake/
289 |
290 | # JetBrains Rider
291 | .idea/
292 | *.sln.iml
293 |
294 | # CodeRush
295 | .cr/
296 |
297 | # Python Tools for Visual Studio (PTVS)
298 | __pycache__/
299 | *.pyc
300 |
301 | # Cake - Uncomment if you are using it
302 | # tools/**
303 | # !tools/packages.config
304 |
305 | # Tabs Studio
306 | *.tss
307 |
308 | # Telerik's JustMock configuration file
309 | *.jmconfig
310 |
311 | # BizTalk build output
312 | *.btp.cs
313 | *.btm.cs
314 | *.odx.cs
315 | *.xsd.cs
316 |
317 | # OpenCover UI analysis results
318 | OpenCover/
319 |
320 | # Azure Stream Analytics local run output
321 | ASALocalRun/
322 |
323 | # MSBuild Binary and Structured Log
324 | *.binlog
325 |
326 | # NVidia Nsight GPU debugger configuration file
327 | *.nvuser
328 |
329 | # MFractors (Xamarin productivity tool) working folder
330 | .mfractor/
331 |
--------------------------------------------------------------------------------
/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.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., label, 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 |
--------------------------------------------------------------------------------
/CosmosTableSamples.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.27130.2036
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CosmosTableSamples", "CosmosTableSamples\CosmosTableSamples.csproj", "{039E3708-8A89-4008-987E-C50958F4C338}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Cover|Any CPU = Cover|Any CPU
11 | Cover|x64 = Cover|x64
12 | Debug|Any CPU = Debug|Any CPU
13 | Debug|x64 = Debug|x64
14 | Release|Any CPU = Release|Any CPU
15 | Release|x64 = Release|x64
16 | EndGlobalSection
17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
18 | {039E3708-8A89-4008-987E-C50958F4C338}.Cover|Any CPU.ActiveCfg = Debug|Any CPU
19 | {039E3708-8A89-4008-987E-C50958F4C338}.Cover|Any CPU.Build.0 = Debug|Any CPU
20 | {039E3708-8A89-4008-987E-C50958F4C338}.Cover|x64.ActiveCfg = Debug|Any CPU
21 | {039E3708-8A89-4008-987E-C50958F4C338}.Cover|x64.Build.0 = Debug|Any CPU
22 | {039E3708-8A89-4008-987E-C50958F4C338}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
23 | {039E3708-8A89-4008-987E-C50958F4C338}.Debug|Any CPU.Build.0 = Debug|Any CPU
24 | {039E3708-8A89-4008-987E-C50958F4C338}.Debug|x64.ActiveCfg = Debug|Any CPU
25 | {039E3708-8A89-4008-987E-C50958F4C338}.Debug|x64.Build.0 = Debug|Any CPU
26 | {039E3708-8A89-4008-987E-C50958F4C338}.Release|Any CPU.ActiveCfg = Release|Any CPU
27 | {039E3708-8A89-4008-987E-C50958F4C338}.Release|Any CPU.Build.0 = Release|Any CPU
28 | {039E3708-8A89-4008-987E-C50958F4C338}.Release|x64.ActiveCfg = Release|Any CPU
29 | {039E3708-8A89-4008-987E-C50958F4C338}.Release|x64.Build.0 = Release|Any CPU
30 | EndGlobalSection
31 | GlobalSection(SolutionProperties) = preSolution
32 | HideSolutionNode = FALSE
33 | EndGlobalSection
34 | GlobalSection(ExtensibilityGlobals) = postSolution
35 | SolutionGuid = {2DACA3A2-20D0-4A48-899F-AE7E1476933A}
36 | EndGlobalSection
37 | EndGlobal
38 |
--------------------------------------------------------------------------------
/CosmosTableSamples/AdvancedSamples.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | namespace CosmosTableSamples
5 | {
6 | using System.Threading;
7 | using System.Threading.Tasks;
8 | using Microsoft.Azure.Cosmos.Table;
9 | using Model;
10 |
11 | class AdvancedSamples
12 | {
13 | public async Task RunSamples()
14 | {
15 | Console.WriteLine("Azure Cosmos DB Table - Advanced Samples\n");
16 | Console.WriteLine();
17 |
18 | string tableName = "demo" + Guid.NewGuid().ToString().Substring(0, 5);
19 |
20 | // Create or reference an existing table
21 | CloudTable table = await Common.CreateTableAsync(tableName);
22 | CloudTableClient tableClient = table.ServiceClient;
23 |
24 | try
25 | {
26 | // Demonstrate advanced functionality such as batch operations and segmented multi-entity queries
27 | await AdvancedDataOperationsAsync(table);
28 |
29 | // List tables in the account
30 | await TableListingOperations(tableClient);
31 |
32 | if (!SamplesUtils.IsAzureCosmosdbTable())
33 | {
34 | // Create a SAS and try CRUD operations with the SAS.
35 | await AdvancedDataOperationsWithSasAsync(table);
36 |
37 | // Service Properties
38 | await ServicePropertiesSample(tableClient);
39 |
40 | // CORS
41 | await CorsSample(tableClient);
42 |
43 | // Service Stats
44 | await ServiceStatsSample(tableClient);
45 |
46 | // Table Acl
47 | await TableAclSample(table);
48 |
49 | // Create a SAS and try CRUD operations with the SAS and shared access policy on the table.
50 | await AdvancedDataOperationsWithSasAndSharedAccessPolicyOnTableAsync(table);
51 | }
52 | }
53 | finally
54 | {
55 | // Delete the table
56 | await table.DeleteIfExistsAsync();
57 | }
58 | }
59 |
60 | private static async Task AdvancedDataOperationsAsync(CloudTable table)
61 | {
62 | // Demonstrate upsert and batch table operations
63 | Console.WriteLine("Inserting a batch of entities. ");
64 | await BatchInsertOfCustomerEntitiesAsync(table, "Smith");
65 | Console.WriteLine();
66 |
67 | // Query a range of data within a partition using a simple query
68 | Console.WriteLine("Retrieving entities with surname of Smith and first names >= 1 and <= 75");
69 | ExecuteSimpleQuery(table, "Smith", "0001", "0075");
70 | Console.WriteLine();
71 |
72 | // Query the same range of data within a partition and return result segments of 50 entities at a time
73 | Console.WriteLine("Retrieving entities with surname of Smith and first names >= 1 and <= 75");
74 | await PartitionRangeQueryAsync(table, "Smith", "0001", "0075");
75 | Console.WriteLine();
76 |
77 | // Query for all the data within a partition
78 | Console.WriteLine("Retrieve entities with surname of Smith.");
79 | await PartitionScanAsync(table, "Smith");
80 | Console.WriteLine();
81 |
82 | if (SamplesUtils.IsAzureCosmosdbTable())
83 | {
84 | // Demonstrate upsert and batch table operations
85 | Console.WriteLine("Inserting a batch of entities. ");
86 | await BatchInsertOfCustomerEntitiesAsync(table, "Dave");
87 | Console.WriteLine();
88 |
89 | // Demonstrate upsert and batch table operations
90 | Console.WriteLine("Inserting a batch of entities. ");
91 | await BatchInsertOfCustomerEntitiesAsync(table, "Shirly");
92 | Console.WriteLine();
93 |
94 | //Query for all the data cross partition with order by
95 | Console.WriteLine("Query with order by cross partition");
96 | await ExecuteCrossPartitionQueryWithOrderBy(table, "0001", "0025");
97 | Console.WriteLine();
98 | }
99 | }
100 |
101 | ///
102 | /// List tables in the account.
103 | ///
104 | /// The table client.
105 | /// A Task object
106 | private static async Task TableListingOperations(CloudTableClient tableClient)
107 | {
108 | try
109 | {
110 | // To list all tables in the account, uncomment the following line.
111 | // Note that listing all tables in the account may take a long time if the account contains a large number of tables.
112 | // ListAllTables(tableClient);
113 |
114 | // List tables beginning with the specified prefix.
115 | await ListTablesWithPrefix(tableClient, "demo");
116 | }
117 | catch (StorageException e)
118 | {
119 | Console.WriteLine(e.Message);
120 | Console.ReadLine();
121 | throw;
122 | }
123 | }
124 |
125 | ///
126 | /// Lists tables in the account whose names begin with the specified prefix.
127 | ///
128 | /// The Table service client object.
129 | /// The table name prefix.
130 | /// A Task object
131 | private static async Task ListTablesWithPrefix(CloudTableClient tableClient, string prefix)
132 | {
133 | Console.WriteLine("List all tables beginning with prefix {0}:", prefix);
134 |
135 | TableContinuationToken continuationToken = null;
136 | TableResultSegment resultSegment = null;
137 |
138 | try
139 | {
140 | do
141 | {
142 | // List tables beginning with the specified prefix.
143 | // Passing in null for the maxResults parameter returns the maximum number of results (up to 5000).
144 | resultSegment = await tableClient.ListTablesSegmentedAsync(
145 | prefix, null, continuationToken, null, null);
146 |
147 | // Enumerate the tables returned.
148 | foreach (var table in resultSegment.Results)
149 | {
150 | Console.WriteLine("\tTable:" + table.Name);
151 | }
152 | }
153 | while (continuationToken != null);
154 | Console.WriteLine();
155 | }
156 | catch (StorageException e)
157 | {
158 | Console.WriteLine(e.Message);
159 | Console.ReadLine();
160 | throw;
161 | }
162 | }
163 |
164 | ///
165 | /// Lists all tables in the account.
166 | ///
167 | /// The Table service client object.
168 | private static void ListAllTables(CloudTableClient tableClient)
169 | {
170 | Console.WriteLine("List all tables in account:");
171 |
172 | try
173 | {
174 | // Note that listing all tables in the account may take a long time if the account contains a large number of tables.
175 | foreach (var table in tableClient.ListTables())
176 | {
177 | Console.WriteLine("\tTable:" + table.Name);
178 | }
179 |
180 | Console.WriteLine();
181 | }
182 | catch (StorageException e)
183 | {
184 | Console.WriteLine(e.Message);
185 | Console.ReadLine();
186 | throw;
187 | }
188 | }
189 |
190 | ///
191 | /// Demonstrate inserting of a large batch of entities. Some considerations for batch operations:
192 | /// 1. You can perform updates, deletes, and inserts in the same single batch operation.
193 | /// 2. A single batch operation can include up to 100 entities.
194 | /// 3. All entities in a single batch operation must have the same partition key.
195 | /// 4. While it is possible to perform a query as a batch operation, it must be the only operation in the batch.
196 | /// 5. Batch size must be less than or equal to 2 MB
197 | ///
198 | /// Sample table name
199 | /// The partition for the entity
200 | /// A Task object
201 | private static async Task BatchInsertOfCustomerEntitiesAsync(CloudTable table, string partitionKey)
202 | {
203 | try
204 | {
205 | // Create the batch operation.
206 | TableBatchOperation batchOperation = new TableBatchOperation();
207 |
208 | // The following code generates test data for use during the query samples.
209 | for (int i = 0; i < 100; i++)
210 | {
211 | batchOperation.InsertOrMerge(new CustomerEntity(partitionKey, string.Format("{0}", i.ToString("D4")))
212 | {
213 | Email = string.Format("{0}@contoso.com", i.ToString("D4")),
214 | PhoneNumber = string.Format("425-555-{0}", i.ToString("D4"))
215 | });
216 | }
217 |
218 | // Execute the batch operation.
219 | TableBatchResult results = await table.ExecuteBatchAsync(batchOperation);
220 | foreach (var res in results)
221 | {
222 | var customerInserted = res.Result as CustomerEntity;
223 | Console.WriteLine("Inserted entity with\t Etag = {0} and PartitionKey = {1}, RowKey = {2}", customerInserted.ETag, customerInserted.PartitionKey, customerInserted.RowKey);
224 | }
225 |
226 | if (results.RequestCharge.HasValue)
227 | {
228 | Console.WriteLine("Request Charge of the Batch Operation against Cosmos DB Table: " + results.RequestCharge);
229 | }
230 | }
231 | catch (StorageException e)
232 | {
233 | Console.WriteLine(e.Message);
234 | Console.ReadLine();
235 | throw;
236 | }
237 | }
238 |
239 | ///
240 | /// Demonstrate a partition range query that searches within a partition for a set of entities that are within a
241 | /// specific range. This query returns all entities in the range. Note that if your table contains a large amount of data,
242 | /// the query may be slow or may time out. In that case, use a segmented query, as shown in the PartitionRangeQueryAsync()
243 | /// sample method.
244 | /// Note that the ExecuteSimpleQuery method is called synchronously, for the purposes of the sample. However, in a real-world
245 | /// application using the async/await pattern, best practices recommend using asynchronous methods consistently.
246 | ///
247 | /// Sample table name
248 | /// The partition within which to search
249 | /// The lowest bound of the row key range within which to search
250 | /// The highest bound of the row key range within which to search
251 | private static void ExecuteSimpleQuery(CloudTable table, string partitionKey, string startRowKey,
252 | string endRowKey)
253 | {
254 | try
255 | {
256 | // Create the range query using the fluid API
257 | TableQuery rangeQuery = new TableQuery().Where(
258 | TableQuery.CombineFilters(
259 | TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, partitionKey),
260 | TableOperators.And,
261 | TableQuery.CombineFilters(
262 | TableQuery.GenerateFilterCondition("RowKey", QueryComparisons.GreaterThanOrEqual,
263 | startRowKey),
264 | TableOperators.And,
265 | TableQuery.GenerateFilterCondition("RowKey", QueryComparisons.LessThanOrEqual,
266 | endRowKey))));
267 |
268 | foreach (CustomerEntity entity in table.ExecuteQuery(rangeQuery))
269 | {
270 | Console.WriteLine("Customer: {0},{1}\t{2}\t{3}", entity.PartitionKey, entity.RowKey, entity.Email,
271 | entity.PhoneNumber);
272 | }
273 | }
274 | catch (StorageException e)
275 | {
276 | Console.WriteLine(e.Message);
277 | Console.ReadLine();
278 | throw;
279 | }
280 | }
281 |
282 | ///
283 | /// Demonstrate a partition range query that searches within a partition for a set of entities that are within a
284 | /// specific range. The async APIs require that the user handle the segment size and return the next segment
285 | /// using continuation tokens.
286 | ///
287 | /// Sample table name
288 | /// The partition within which to search
289 | /// The lowest bound of the row key range within which to search
290 | /// The highest bound of the row key range within which to search
291 | /// A Task object
292 | private static async Task PartitionRangeQueryAsync(CloudTable table, string partitionKey, string startRowKey, string endRowKey)
293 | {
294 | try
295 | {
296 | // Create the range query using the fluid API
297 | TableQuery rangeQuery = new TableQuery().Where(
298 | TableQuery.CombineFilters(
299 | TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, partitionKey),
300 | TableOperators.And,
301 | TableQuery.CombineFilters(
302 | TableQuery.GenerateFilterCondition("RowKey", QueryComparisons.GreaterThanOrEqual, startRowKey),
303 | TableOperators.And,
304 | TableQuery.GenerateFilterCondition("RowKey", QueryComparisons.LessThanOrEqual, endRowKey))));
305 |
306 | // Request 50 results at a time from the server.
307 | TableContinuationToken token = null;
308 | rangeQuery.TakeCount = 50;
309 | int segmentNumber = 0;
310 | do
311 | {
312 | // Execute the query, passing in the continuation token.
313 | // The first time this method is called, the continuation token is null. If there are more results, the call
314 | // populates the continuation token for use in the next call.
315 | TableQuerySegment segment = await table.ExecuteQuerySegmentedAsync(rangeQuery, token);
316 |
317 | // Indicate which segment is being displayed
318 | if (segment.Results.Count > 0)
319 | {
320 | segmentNumber++;
321 | Console.WriteLine();
322 | Console.WriteLine("Segment {0}", segmentNumber);
323 | }
324 |
325 | // Save the continuation token for the next call to ExecuteQuerySegmentedAsync
326 | token = segment.ContinuationToken;
327 |
328 | // Write out the properties for each entity returned.
329 | foreach (CustomerEntity entity in segment)
330 | {
331 | Console.WriteLine("\t Customer: {0},{1}\t{2}\t{3}", entity.PartitionKey, entity.RowKey, entity.Email, entity.PhoneNumber);
332 | }
333 |
334 | Console.WriteLine();
335 | }
336 | while (token != null);
337 | }
338 | catch (StorageException e)
339 | {
340 | Console.WriteLine(e.Message);
341 | Console.ReadLine();
342 | throw;
343 | }
344 | }
345 |
346 | ///
347 | /// Demonstrate a partition scan whereby we are searching for all the entities within a partition. Note this is not as efficient
348 | /// as a range scan - but definitely more efficient than a full table scan. The async APIs require that the user handle the segment
349 | /// size and return the next segment using continuation tokens.
350 | ///
351 | /// Sample table name
352 | /// The partition within which to search
353 | /// A Task object
354 | private static async Task PartitionScanAsync(CloudTable table, string partitionKey)
355 | {
356 | try
357 | {
358 | TableQuery partitionScanQuery =
359 | new TableQuery().Where(TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, partitionKey));
360 |
361 | TableContinuationToken token = null;
362 |
363 | // Read entities from each query segment.
364 | do
365 | {
366 | TableQuerySegment segment = await table.ExecuteQuerySegmentedAsync(partitionScanQuery, token);
367 | token = segment.ContinuationToken;
368 | foreach (CustomerEntity entity in segment)
369 | {
370 | Console.WriteLine("Customer: {0},{1}\t{2}\t{3}", entity.PartitionKey, entity.RowKey, entity.Email, entity.PhoneNumber);
371 | }
372 | }
373 | while (token != null);
374 | }
375 | catch (StorageException e)
376 | {
377 | Console.WriteLine(e.Message);
378 | Console.ReadLine();
379 | throw;
380 | }
381 | }
382 |
383 | ///
384 | /// Demonstrate a cross partition query with order by against Cosmos Table API
385 | ///
386 | /// Sample table name
387 | /// The lowest bound of the row key range within which to search
388 | /// The highest bound of the row key range within which to search
389 | /// A Task object
390 | private static async Task ExecuteCrossPartitionQueryWithOrderBy(CloudTable table, string startRowKey, string endRowKey)
391 | {
392 | try
393 | {
394 | TableQuery partitionScanQuery =
395 | new TableQuery().Where(
396 | TableQuery.CombineFilters(
397 | TableQuery.GenerateFilterCondition("RowKey", QueryComparisons.GreaterThanOrEqual, startRowKey),
398 | TableOperators.And,
399 | TableQuery.GenerateFilterCondition("RowKey", QueryComparisons.LessThanOrEqual, endRowKey)
400 | )
401 | )
402 | .OrderBy("RowKey");
403 |
404 | TableContinuationToken token = null;
405 |
406 | // Read entities from each query segment.
407 | do
408 | {
409 | TableQuerySegment segment = await table.ExecuteQuerySegmentedAsync(partitionScanQuery, token);
410 |
411 | if (segment.RequestCharge.HasValue)
412 | {
413 | Console.WriteLine("Request Charge for Query Operation: " + segment.RequestCharge);
414 | }
415 |
416 | token = segment.ContinuationToken;
417 | foreach (CustomerEntity entity in segment)
418 | {
419 | Console.WriteLine("Customer: {0},{1}\t{2}\t{3}", entity.PartitionKey, entity.RowKey, entity.Email, entity.PhoneNumber);
420 | }
421 | }
422 | while (token != null);
423 | }
424 | catch (StorageException e)
425 | {
426 | Console.WriteLine(e.Message);
427 | Console.ReadLine();
428 | throw;
429 | }
430 | }
431 |
432 | ///
433 | /// Manage the properties of the Table service.
434 | ///
435 | ///
436 | private static async Task ServicePropertiesSample(CloudTableClient tableClient)
437 | {
438 | Console.WriteLine();
439 |
440 | // Get service properties
441 | Console.WriteLine("Get service properties");
442 | ServiceProperties originalProperties = await tableClient.GetServicePropertiesAsync();
443 | try
444 | {
445 | // Set service properties
446 | Console.WriteLine("Set service properties");
447 |
448 | ServiceProperties props = await tableClient.GetServicePropertiesAsync();
449 | props.Logging.LoggingOperations = LoggingOperations.Read | LoggingOperations.Write;
450 | props.Logging.RetentionDays = 5;
451 | props.Logging.Version = "1.0";
452 |
453 | props.HourMetrics.MetricsLevel = MetricsLevel.Service;
454 | props.HourMetrics.RetentionDays = 6;
455 | props.HourMetrics.Version = "1.0";
456 |
457 | props.MinuteMetrics.MetricsLevel = MetricsLevel.Service;
458 | props.MinuteMetrics.RetentionDays = 6;
459 | props.MinuteMetrics.Version = "1.0";
460 |
461 | await tableClient.SetServicePropertiesAsync(props);
462 | }
463 | finally
464 | {
465 | // Revert back to original service properties
466 | Console.WriteLine("Revert back to original service properties");
467 | await tableClient.SetServicePropertiesAsync(originalProperties);
468 | }
469 | Console.WriteLine();
470 | }
471 |
472 | ///
473 | /// Query the Cross-Origin Resource Sharing (CORS) rules for the Table service
474 | ///
475 | ///
476 | private static async Task CorsSample(CloudTableClient tableClient)
477 | {
478 | Console.WriteLine();
479 |
480 | // Get service properties
481 | Console.WriteLine("Get service properties");
482 | ServiceProperties originalProperties = await tableClient.GetServicePropertiesAsync();
483 | try
484 | {
485 | // Add CORS rule
486 | Console.WriteLine("Add CORS rule");
487 |
488 | CorsRule corsRule = new CorsRule
489 | {
490 | AllowedHeaders = new List { "*" },
491 | AllowedMethods = CorsHttpMethods.Get,
492 | AllowedOrigins = new List { "*" },
493 | ExposedHeaders = new List { "*" },
494 | MaxAgeInSeconds = 3600
495 | };
496 |
497 | ServiceProperties serviceProperties = await tableClient.GetServicePropertiesAsync();
498 | serviceProperties.Cors.CorsRules.Add(corsRule);
499 | await tableClient.SetServicePropertiesAsync(serviceProperties);
500 | }
501 | finally
502 | {
503 | // Revert back to original service properties
504 | Console.WriteLine("Revert back to original service properties");
505 | await tableClient.SetServicePropertiesAsync(originalProperties);
506 | }
507 | Console.WriteLine();
508 | }
509 |
510 | ///
511 | /// Retrieve statistics related to replication for the Table service
512 | ///
513 | ///
514 | private static async Task ServiceStatsSample(CloudTableClient tableClient)
515 | {
516 | Console.WriteLine();
517 |
518 | var originalLocation = tableClient.DefaultRequestOptions.LocationMode;
519 |
520 | Console.WriteLine("Service stats:");
521 | try
522 | {
523 | tableClient.DefaultRequestOptions.LocationMode = LocationMode.SecondaryOnly;
524 | ServiceStats stats = await tableClient.GetServiceStatsAsync();
525 | Console.WriteLine(" Last sync time: {0}", stats.GeoReplication.LastSyncTime);
526 | Console.WriteLine(" Status: {0}", stats.GeoReplication.Status);
527 | }
528 | catch (StorageException)
529 | {
530 | // only works on RA-GRS (Read Access – Geo Redundant Storage)
531 | }
532 | finally
533 | {
534 | // Restore original value
535 | tableClient.DefaultRequestOptions.LocationMode = originalLocation;
536 | }
537 |
538 | Console.WriteLine();
539 | }
540 |
541 | ///
542 | /// Manage stored access policies specified on the table
543 | ///
544 | ///
545 | ///
546 | private static async Task TableAclSample(CloudTable table)
547 | {
548 | // Set table permissions
549 | SharedAccessTablePolicy accessTablePolicy = new SharedAccessTablePolicy();
550 | accessTablePolicy.SharedAccessStartTime = new DateTimeOffset(DateTime.Now);
551 | accessTablePolicy.SharedAccessExpiryTime = new DateTimeOffset(DateTime.Now.AddMinutes(10));
552 | accessTablePolicy.Permissions = SharedAccessTablePermissions.Update;
553 | TablePermissions permissions = new TablePermissions();
554 | permissions.SharedAccessPolicies.Add("key1", accessTablePolicy);
555 | Console.WriteLine("Set table permissions");
556 | await table.SetPermissionsAsync(permissions);
557 |
558 | // Get table permissions
559 | Console.WriteLine("Get table permissions:");
560 | permissions = await table.GetPermissionsAsync();
561 | foreach (var keyValue in permissions.SharedAccessPolicies)
562 | {
563 | Console.WriteLine(" {0}:", keyValue.Key);
564 | Console.WriteLine(" permissions: {0}:", keyValue.Value.Permissions);
565 | Console.WriteLine(" start time: {0}:", keyValue.Value.SharedAccessStartTime);
566 | Console.WriteLine(" expiry time: {0}:", keyValue.Value.SharedAccessExpiryTime);
567 | }
568 | }
569 |
570 | ///
571 | /// Demonstrates basic CRUD operations using a SAS for authentication.
572 | ///
573 | /// The table.
574 | /// A Task object
575 | private static async Task AdvancedDataOperationsWithSasAsync(CloudTable table)
576 | {
577 | // Generate an ad-hoc SAS on the table, then test the SAS. It permits all CRUD operations on the table.
578 | string adHocTableSAS = GetTableSasUri(table);
579 |
580 | // Create an instance of a customer entity.
581 | CustomerEntity customer1 = new CustomerEntity("Johnson", "Mary")
582 | {
583 | Email = "mary@contoso.com",
584 | PhoneNumber = "425-555-0105"
585 | };
586 | await TestTableSAS(adHocTableSAS, customer1);
587 | }
588 |
589 |
590 | ///
591 | /// Demonstrates basic CRUD operations using a SAS for authentication.
592 | ///
593 | /// The table.
594 | /// A Task object
595 | private static async Task AdvancedDataOperationsWithSasAndSharedAccessPolicyOnTableAsync(CloudTable table)
596 | {
597 | string sharedAccessPolicyName = "sample-policy";
598 |
599 | // Create a shared access policy on the table.
600 | // The access policy may be optionally used to provide constraints for
601 | // shared access signatures on the table.
602 | await CreateSharedAccessPolicy(table, sharedAccessPolicyName);
603 |
604 | // Generate a SAS URI for the table, using the stored access policy to set constraints on the SAS.
605 | // Then test the SAS. All CRUD operations should succeed.
606 | string sharedPolicyTableSAS = GetTableSasUri(table, sharedAccessPolicyName);
607 |
608 | // Create an instance of a customer entity.
609 | CustomerEntity customer2 = new CustomerEntity("Wilson", "Joe")
610 | {
611 | Email = "joe@contoso.com",
612 | PhoneNumber = "425-555-0106"
613 | };
614 | await TestTableSAS(sharedPolicyTableSAS, customer2);
615 | }
616 |
617 | ///
618 | /// Returns a URI containing a SAS for the table.
619 | ///
620 | /// A CloudTable object.
621 | /// A string containing the name of the stored access policy. If null, an ad-hoc SAS is created.
622 | /// A string containing the URI for the table, with the SAS token appended.
623 | private static string GetTableSasUri(CloudTable table, string storedPolicyName = null)
624 | {
625 | string sasTableToken;
626 |
627 | // If no stored policy is specified, create a new access policy and define its constraints.
628 | if (storedPolicyName == null)
629 | {
630 | // Note that the SharedAccessTablePolicy class is used both to define the parameters of an ad-hoc SAS, and
631 | // to construct a shared access policy that is saved to the table's shared access policies.
632 | SharedAccessTablePolicy adHocPolicy = new SharedAccessTablePolicy()
633 | {
634 | // Permissions enable users to add, update, query, and delete entities in the table.
635 | SharedAccessExpiryTime = DateTime.UtcNow.AddHours(24),
636 | Permissions = SharedAccessTablePermissions.Add | SharedAccessTablePermissions.Update |
637 | SharedAccessTablePermissions.Query | SharedAccessTablePermissions.Delete
638 | };
639 |
640 | // Generate the shared access signature on the table, setting the constraints directly on the signature.
641 | sasTableToken = table.GetSharedAccessSignature(adHocPolicy, null);
642 |
643 | Console.WriteLine("SAS for table (ad hoc): {0}", sasTableToken);
644 | Console.WriteLine();
645 | }
646 | else
647 | {
648 | // Generate the shared access signature on the table. In this case, all of the constraints for the
649 | // shared access signature are specified on the stored access policy, which is provided by name.
650 | // It is also possible to specify some constraints on an ad-hoc SAS and others on the stored access policy.
651 | // However, a constraint must be specified on one or the other; it cannot be specified on both.
652 | sasTableToken = table.GetSharedAccessSignature(null, storedPolicyName);
653 |
654 | Console.WriteLine("SAS for table (stored access policy): {0}", sasTableToken);
655 | Console.WriteLine();
656 | }
657 |
658 | // Return the URI string for the table, including the SAS token.
659 | return table.Uri + sasTableToken;
660 | }
661 |
662 | ///
663 | /// Creates a shared access policy on the table.
664 | ///
665 | /// A CloudTable object.
666 | /// The name of the stored access policy.
667 | /// A Task object
668 | private static async Task CreateSharedAccessPolicy(CloudTable table, string policyName)
669 | {
670 | // Create a new shared access policy and define its constraints.
671 | // The access policy provides add, update, and query permissions.
672 | SharedAccessTablePolicy sharedPolicy = new SharedAccessTablePolicy()
673 | {
674 | // Permissions enable users to add, update, query, and delete entities in the table.
675 | SharedAccessExpiryTime = DateTime.UtcNow.AddHours(24),
676 | Permissions = SharedAccessTablePermissions.Add | SharedAccessTablePermissions.Update |
677 | SharedAccessTablePermissions.Query | SharedAccessTablePermissions.Delete
678 | };
679 |
680 | try
681 | {
682 | // Get the table's existing permissions.
683 | TablePermissions permissions = await table.GetPermissionsAsync();
684 |
685 | // Add the new policy to the table's permissions, and update the table's permissions.
686 | permissions.SharedAccessPolicies.Add(policyName, sharedPolicy);
687 | await table.SetPermissionsAsync(permissions);
688 |
689 | Console.WriteLine("Wait 30 seconds for pemissions to propagate");
690 | Thread.Sleep(30);
691 | }
692 | catch (StorageException e)
693 | {
694 | Console.WriteLine(e.Message);
695 | Console.ReadLine();
696 | throw;
697 | }
698 | }
699 |
700 | ///
701 | /// Tests a table SAS to determine which operations it allows.
702 | ///
703 | /// A string containing a URI with a SAS appended.
704 | /// The customer entity.
705 | /// A Task object
706 | private static async Task TestTableSAS(string sasUri, CustomerEntity customer)
707 | {
708 | // Try performing table operations with the SAS provided.
709 | // Note that the storage account credentials are not required here; the SAS provides the necessary
710 | // authentication information on the URI.
711 |
712 | // Return a reference to the table using the SAS URI.
713 | CloudTable table = new CloudTable(new Uri(sasUri));
714 |
715 | // Upsert (add/update) operations: insert an entity.
716 | // This operation requires both add and update permissions on the SAS.
717 | try
718 | {
719 | // Insert the new entity.
720 | customer = await SamplesUtils.InsertOrMergeEntityAsync(table, customer);
721 |
722 | Console.WriteLine("Add operation succeeded for SAS {0}", sasUri);
723 | Console.WriteLine();
724 | }
725 | catch (StorageException e)
726 | {
727 | if (e.RequestInformation.HttpStatusCode == 403)
728 | {
729 | Console.WriteLine("Add operation failed for SAS {0}", sasUri);
730 | Console.WriteLine("Additional error information: " + e.Message);
731 | Console.WriteLine();
732 | }
733 | else
734 | {
735 | Console.WriteLine(e.Message);
736 | Console.ReadLine();
737 | throw;
738 | }
739 | }
740 |
741 | // Read operation: query an entity.
742 | // This operation requires read permissions on the SAS.
743 | CustomerEntity customerRead = null;
744 | try
745 | {
746 | TableOperation retrieveOperation = TableOperation.Retrieve(customer.PartitionKey, customer.RowKey);
747 | TableResult result = await table.ExecuteAsync(retrieveOperation);
748 | customerRead = result.Result as CustomerEntity;
749 | if (customerRead != null)
750 | {
751 | Console.WriteLine("\t{0}\t{1}\t{2}\t{3}", customerRead.PartitionKey, customerRead.RowKey, customerRead.Email, customerRead.PhoneNumber);
752 | }
753 |
754 | Console.WriteLine("Read operation succeeded for SAS {0}", sasUri);
755 | Console.WriteLine();
756 | }
757 | catch (StorageException e)
758 | {
759 | if (e.RequestInformation.HttpStatusCode == 403)
760 | {
761 | Console.WriteLine("Read operation failed for SAS {0}", sasUri);
762 | Console.WriteLine("Additional error information: " + e.Message);
763 | Console.WriteLine();
764 | }
765 | else
766 | {
767 | Console.WriteLine(e.Message);
768 | Console.ReadLine();
769 | throw;
770 | }
771 | }
772 |
773 | // Delete operation: delete an entity.
774 | try
775 | {
776 | if (customerRead != null)
777 | {
778 | await SamplesUtils.DeleteEntityAsync(table, customerRead);
779 | }
780 |
781 | Console.WriteLine("Delete operation succeeded for SAS {0}", sasUri);
782 | Console.WriteLine();
783 | }
784 | catch (StorageException e)
785 | {
786 | if (e.RequestInformation.HttpStatusCode == 403)
787 | {
788 | Console.WriteLine("Delete operation failed for SAS {0}", sasUri);
789 | Console.WriteLine("Additional error information: " + e.Message);
790 | Console.WriteLine();
791 | }
792 | else
793 | {
794 | Console.WriteLine(e.Message);
795 | Console.ReadLine();
796 | throw;
797 | }
798 | }
799 |
800 | Console.WriteLine();
801 | }
802 | }
803 | }
804 |
--------------------------------------------------------------------------------
/CosmosTableSamples/AppSettings.cs:
--------------------------------------------------------------------------------
1 | namespace CosmosTableSamples
2 | {
3 | using Microsoft.Extensions.Configuration;
4 |
5 | public class AppSettings
6 | {
7 | public string StorageConnectionString { get; set; }
8 |
9 | public static AppSettings LoadAppSettings()
10 | {
11 | IConfigurationRoot configRoot = new ConfigurationBuilder()
12 | .AddJsonFile("Settings.json")
13 | .Build();
14 | AppSettings appSettings = configRoot.Get();
15 | return appSettings;
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/CosmosTableSamples/BasicSamples.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace CosmosTableSamples
4 | {
5 | using System.Threading.Tasks;
6 | using Microsoft.Azure.Cosmos.Table;
7 | using Model;
8 |
9 | class BasicSamples
10 | {
11 | public async Task RunSamples()
12 | {
13 | Console.WriteLine("Azure Cosmos DB Table - Basic Samples\n");
14 | Console.WriteLine();
15 |
16 | string tableName = "demo" + Guid.NewGuid().ToString().Substring(0, 5);
17 |
18 | // Create or reference an existing table
19 | CloudTable table = await Common.CreateTableAsync(tableName);
20 |
21 | try
22 | {
23 | // Demonstrate basic CRUD functionality
24 | await BasicDataOperationsAsync(table);
25 | }
26 | finally
27 | {
28 | // Delete the table
29 | await table.DeleteIfExistsAsync();
30 | }
31 | }
32 |
33 | private static async Task BasicDataOperationsAsync(CloudTable table)
34 | {
35 | // Create an instance of a customer entity. See the Model\CustomerEntity.cs for a description of the entity.
36 | CustomerEntity customer = new CustomerEntity("Harp", "Walter")
37 | {
38 | Email = "Walter@contoso.com",
39 | PhoneNumber = "425-555-0101"
40 | };
41 |
42 | // Demonstrate how to insert the entity
43 | Console.WriteLine("Insert an Entity.");
44 | customer = await SamplesUtils.InsertOrMergeEntityAsync(table, customer);
45 |
46 | // Demonstrate how to Update the entity by changing the phone number
47 | Console.WriteLine("Update an existing Entity using the InsertOrMerge Upsert Operation.");
48 | customer.PhoneNumber = "425-555-0105";
49 | await SamplesUtils.InsertOrMergeEntityAsync(table, customer);
50 | Console.WriteLine();
51 |
52 | // Demonstrate how to Read the updated entity using a point query
53 | Console.WriteLine("Reading the updated Entity.");
54 | customer = await SamplesUtils.RetrieveEntityUsingPointQueryAsync(table, "Harp", "Walter");
55 | Console.WriteLine();
56 |
57 | // Demonstrate how to Delete an entity
58 | Console.WriteLine("Delete the entity. ");
59 | await SamplesUtils.DeleteEntityAsync(table, customer);
60 | Console.WriteLine();
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/CosmosTableSamples/Common.cs:
--------------------------------------------------------------------------------
1 | //
2 | using System;
3 |
4 | namespace CosmosTableSamples
5 | {
6 | using System.Threading.Tasks;
7 | using Microsoft.Azure.Cosmos.Table;
8 | using Microsoft.Azure.Documents;
9 |
10 | public class Common
11 | {
12 | public static CloudStorageAccount CreateStorageAccountFromConnectionString(string storageConnectionString)
13 | {
14 | CloudStorageAccount storageAccount;
15 | try
16 | {
17 | storageAccount = CloudStorageAccount.Parse(storageConnectionString);
18 | }
19 | catch (FormatException)
20 | {
21 | Console.WriteLine("Invalid storage account information provided. Please confirm the AccountName and AccountKey are valid in the app.config file - then restart the application.");
22 | throw;
23 | }
24 | catch (ArgumentException)
25 | {
26 | Console.WriteLine("Invalid storage account information provided. Please confirm the AccountName and AccountKey are valid in the app.config file - then restart the sample.");
27 | Console.ReadLine();
28 | throw;
29 | }
30 |
31 | return storageAccount;
32 | }
33 | //
34 |
35 | //
36 | public static async Task CreateTableAsync(string tableName)
37 | {
38 | string storageConnectionString = AppSettings.LoadAppSettings().StorageConnectionString;
39 |
40 | // Retrieve storage account information from connection string.
41 | CloudStorageAccount storageAccount = CreateStorageAccountFromConnectionString(storageConnectionString);
42 |
43 | // Create a table client for interacting with the table service
44 | CloudTableClient tableClient = storageAccount.CreateCloudTableClient(new TableClientConfiguration());
45 |
46 | Console.WriteLine("Create a Table for the demo");
47 |
48 | // Create a table client for interacting with the table service
49 | CloudTable table = tableClient.GetTableReference(tableName);
50 | if (await table.CreateIfNotExistsAsync())
51 | {
52 | Console.WriteLine("Created Table named: {0}", tableName);
53 | }
54 | else
55 | {
56 | Console.WriteLine("Table {0} already exists", tableName);
57 | }
58 |
59 | Console.WriteLine();
60 | return table;
61 | }
62 | //
63 |
64 | public static async Task CreateTableAsync(CloudTableClient tableClient, string tableName)
65 | {
66 | Console.WriteLine("Create a Table for the demo");
67 |
68 | // Create a table client for interacting with the table service
69 | CloudTable table = tableClient.GetTableReference(tableName);
70 | try
71 | {
72 | if (await table.CreateIfNotExistsAsync())
73 | {
74 | Console.WriteLine("Created Table named: {0}", tableName);
75 | }
76 | else
77 | {
78 | Console.WriteLine("Table {0} already exists", tableName);
79 | }
80 | }
81 | catch (StorageException)
82 | {
83 | Console.WriteLine(
84 | "If you are running with the default configuration please make sure you have started the storage emulator. Press the Windows key and type Azure Storage to select and run it from the list of applications - then restart the sample.");
85 | Console.ReadLine();
86 | throw;
87 | }
88 | catch (Exception e)
89 | {
90 | Console.WriteLine(e);
91 | }
92 |
93 | Console.WriteLine();
94 | return table;
95 | }
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/CosmosTableSamples/CosmosTableSamples.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | netcoreapp2.0
6 | CosmosTableSamples
7 | CosmosTableSamples
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | PreserveNewest
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/CosmosTableSamples/Model/CustomerEntity.cs:
--------------------------------------------------------------------------------
1 | namespace CosmosTableSamples.Model
2 | {
3 | using Microsoft.Azure.Cosmos.Table;
4 |
5 | public class CustomerEntity : TableEntity
6 | {
7 | public CustomerEntity()
8 | {
9 | }
10 |
11 | public CustomerEntity(string lastName, string firstName)
12 | {
13 | PartitionKey = lastName;
14 | RowKey = firstName;
15 | }
16 |
17 | public string Email { get; set; }
18 |
19 | public string PhoneNumber { get; set; }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/CosmosTableSamples/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace CosmosTableSamples
4 | {
5 | class Program
6 | {
7 | public static void Main(string[] args)
8 | {
9 | Console.WriteLine("Azure Cosmos Table Samples");
10 | BasicSamples basicSamples = new BasicSamples();
11 | basicSamples.RunSamples().Wait();
12 |
13 | AdvancedSamples advancedSamples = new AdvancedSamples();
14 | advancedSamples.RunSamples().Wait();
15 |
16 | Console.WriteLine();
17 | Console.WriteLine("Press any key to exit");
18 | Console.Read();
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/CosmosTableSamples/SamplesUtils.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace CosmosTableSamples
4 | {
5 | using System.Threading.Tasks;
6 | using Microsoft.Azure.Cosmos.Table;
7 | using Model;
8 |
9 | class SamplesUtils
10 | {
11 | //
12 | public static async Task RetrieveEntityUsingPointQueryAsync(CloudTable table, string partitionKey, string rowKey)
13 | {
14 | try
15 | {
16 | TableOperation retrieveOperation = TableOperation.Retrieve(partitionKey, rowKey);
17 | TableResult result = await table.ExecuteAsync(retrieveOperation);
18 | CustomerEntity customer = result.Result as CustomerEntity;
19 | if (customer != null)
20 | {
21 | Console.WriteLine("\t{0}\t{1}\t{2}\t{3}", customer.PartitionKey, customer.RowKey, customer.Email, customer.PhoneNumber);
22 | }
23 |
24 | if (result.RequestCharge.HasValue)
25 | {
26 | Console.WriteLine("Request Charge of Retrieve Operation: " + result.RequestCharge);
27 | }
28 |
29 | return customer;
30 | }
31 | catch (StorageException e)
32 | {
33 | Console.WriteLine(e.Message);
34 | Console.ReadLine();
35 | throw;
36 | }
37 | }
38 | //
39 |
40 | //
41 | public static async Task InsertOrMergeEntityAsync(CloudTable table, CustomerEntity entity)
42 | {
43 | if (entity == null)
44 | {
45 | throw new ArgumentNullException("entity");
46 | }
47 |
48 | try
49 | {
50 | // Create the InsertOrReplace table operation
51 | TableOperation insertOrMergeOperation = TableOperation.InsertOrMerge(entity);
52 |
53 | // Execute the operation.
54 | TableResult result = await table.ExecuteAsync(insertOrMergeOperation);
55 | CustomerEntity insertedCustomer = result.Result as CustomerEntity;
56 |
57 | if (result.RequestCharge.HasValue)
58 | {
59 | Console.WriteLine("Request Charge of InsertOrMerge Operation: " + result.RequestCharge);
60 | }
61 |
62 | return insertedCustomer;
63 | }
64 | catch (StorageException e)
65 | {
66 | Console.WriteLine(e.Message);
67 | Console.ReadLine();
68 | throw;
69 | }
70 | }
71 | //
72 |
73 | //
74 | public static async Task DeleteEntityAsync(CloudTable table, CustomerEntity deleteEntity)
75 | {
76 | try
77 | {
78 | if (deleteEntity == null)
79 | {
80 | throw new ArgumentNullException("deleteEntity");
81 | }
82 |
83 | TableOperation deleteOperation = TableOperation.Delete(deleteEntity);
84 | TableResult result = await table.ExecuteAsync(deleteOperation);
85 |
86 | if (result.RequestCharge.HasValue)
87 | {
88 | Console.WriteLine("Request Charge of Delete Operation: " + result.RequestCharge);
89 | }
90 |
91 | }
92 | catch (StorageException e)
93 | {
94 | Console.WriteLine(e.Message);
95 | Console.ReadLine();
96 | throw;
97 | }
98 | }
99 | //
100 |
101 | ///
102 | /// Check if given connection string is for Azure Table storage or Azure CosmosDB Table.
103 | ///
104 | /// true if azure cosmosdb table
105 | public static bool IsAzureCosmosdbTable()
106 | {
107 | string storageConnectionString = AppSettings.LoadAppSettings().StorageConnectionString;
108 | return !String.IsNullOrEmpty(storageConnectionString) && (storageConnectionString.Contains("table.cosmosdb") || storageConnectionString.Contains("table.cosmos"));
109 | }
110 | }
111 | }
112 |
--------------------------------------------------------------------------------
/CosmosTableSamples/Settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "StorageConnectionString": ""
3 | }
4 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) Microsoft Corporation. All rights reserved.
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
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | page_type: sample
3 | languages:
4 | - csharp
5 | products:
6 | - azure
7 | description: "This .net core sample demonstrates how to perform common tasks using Azure Cosmos DB Table API with .NET Standard SDK including creating a table, CRUD operation, batch operation and different querying techniques. "
8 | urlFragment: azure-cosmos-table-dotnet-core-getting-started
9 | ---
10 |
11 | # Cosmos DB Table API .NET Core Sample
12 |
13 | This .net core sample demonstrates how to perform common tasks using Azure Cosmos DB Table API with .NET Standard SDK including creating a table, CRUD operation, batch operation and different querying techniques.
14 |
15 |
16 | ### Quickstart
17 | (steps to get up and running quickly)
18 |
19 | 1. Open in Visual Studio and do package restore for Nuget.
20 | 2. Open Settings.json and enter your Cosmos DB connection string.
21 |
22 |
23 |
24 | ## Resources
25 |
26 | (Additional resources or related projects)
27 |
28 | - To learn more about the Azure Cosmos DB Table API, see [Introduction to Azure Cosmos DB Table API](table-introduction.md).
29 |
--------------------------------------------------------------------------------