├── .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 | --------------------------------------------------------------------------------