├── .dockerignore ├── .gitignore ├── CODE_OF_CONDUCT.md ├── HandsOn.md ├── LICENSE ├── ManagedIdentity.md ├── README.md ├── SECURITY.md ├── SUPPORT.md ├── media ├── AddRoleAssignment.png ├── DBHelperBanner.png ├── UserAssignedManagedIdentity.png ├── UserAssignedManagedIdentity2.png ├── Worker Generate Constructor.png ├── add entity class.png ├── add reference changefeed.png ├── add reference.png ├── add todoservice class.png ├── azure-cosmos-db-create-new-account-detail.png ├── dotnet new console.png ├── dotnet new worker.png ├── generate constructor.png ├── nuget package manager.png ├── override OnChangeFeedDataSets.png ├── provision cosmosdb mongo.png ├── switch directory add package.png ├── switch directory add package2.png └── worker project.png └── src ├── Libraries ├── Microsoft.Solutions.CosmosDB.Mongo │ ├── BusinessTransactionRepository.cs │ ├── Microsoft.Solutions.CosmosDB.Mongo.csproj │ └── MongoEntntyCollectionBase.cs ├── Microsoft.Solutions.CosmosDB.SQL.ChangeFeed │ ├── ChangeFeedProcessorHelper.cs │ ├── Microsoft.Solutions.CosmosDB.SQL.ChangeFeed.csproj │ └── Watcher.cs ├── Microsoft.Solutions.CosmosDB.SQL │ ├── BusinessTransactionRepository.cs │ ├── Microsoft.Solutions.CosmosDB.SQL.csproj │ └── SQLEntityCollectionBase.cs ├── Microsoft.Solutions.CosmosDB.Test │ ├── CosmosDBTest.cs │ └── Microsoft.Solutions.CosmosDB.Test.csproj └── Microsoft.Solutions.CosmosDB │ ├── CosmosDBEntityBase.cs │ ├── GenericSpecification.cs │ ├── IDataRepositoryProvider.cs │ ├── IEntityModel.cs │ ├── IRepository.cs │ ├── ISpecification.cs │ └── Microsoft.Solutions.CosmosDB.csproj ├── Microsoft CosmosDB Solution Accelerator.sln ├── Sample ├── Microsoft.Solutions.CosmosDB.Mongo.TODO.Service │ ├── Microsoft.Solutions.CosmosDB.Mongo.TODO.Service.csproj │ ├── Models │ │ └── TODO.cs │ └── TODOService.cs ├── Microsoft.Solutions.CosmosDB.Mongo.TODO.Tests │ ├── Microsoft.Solutions.CosmosDB.Mongo.TODO.Tests.csproj │ └── TODOServiceTests.cs ├── Microsoft.Solutions.CosmosDB.SQL.ChangeFeed.Service │ ├── Dockerfile │ ├── Microsoft.Solutions.CosmosDB.SQL.ChangeFeed.Service.csproj │ ├── Models │ │ └── TODO.cs │ ├── Program.cs │ ├── Properties │ │ └── launchSettings.json │ ├── Worker.cs │ ├── appsettings.Development.json │ └── appsettings.json ├── Microsoft.Solutions.CosmosDB.SQL.SDK.TODO.Service.Tests │ ├── Microsoft.Solutions.CosmosDB.SQL.TODO.Service.Tests.csproj │ └── TODOServiceTests.cs ├── Microsoft.Solutions.CosmosDB.SQL.SDK.TODO.Service │ ├── Microsoft.Solutions.CosmosDB.SQL.TODO.Service.csproj │ ├── Models │ │ └── TODO.cs │ └── TODOService.cs └── Microsoft.Solutions.CosmosDB.WebHost │ ├── Controllers │ └── ToDoController.cs │ ├── Dockerfile │ ├── Microsoft.Solutions.CosmosDB.TODO.WebHost.csproj │ ├── Program.cs │ ├── Properties │ └── launchSettings.json │ ├── Startup.cs │ ├── appsettings.Development.json │ ├── appsettings.json │ ├── azds.yaml │ └── charts │ └── microsoftsolutionscosmosdbwebhost │ ├── .helmignore │ ├── Chart.yaml │ ├── templates │ ├── NOTES.txt │ ├── _helpers.tpl │ ├── deployment.yaml │ ├── ingress.yaml │ ├── secrets.yaml │ └── service.yaml │ └── values.yaml ├── Utils └── Microsoft.Solutions.HTTP │ ├── HttpClient.cs │ └── Microsoft.Solutions.HTTP.csproj └── libraries └── Microsoft.Solutions.CosmosDB.Security.ManagedIdentity ├── ConnectionStringAccessor.cs └── Microsoft.Solutions.CosmosDB.Security.ManagedIdentity.csproj /.dockerignore: -------------------------------------------------------------------------------- 1 | **/.classpath 2 | **/.dockerignore 3 | **/.env 4 | **/.git 5 | **/.gitignore 6 | **/.project 7 | **/.settings 8 | **/.toolstarget 9 | **/.vs 10 | **/.vscode 11 | **/*.*proj.user 12 | **/*.dbmdl 13 | **/*.jfm 14 | **/azds.yaml 15 | **/bin 16 | **/charts 17 | **/docker-compose* 18 | **/Dockerfile* 19 | **/node_modules 20 | **/npm-debug.log 21 | **/obj 22 | **/secrets.dev.yaml 23 | **/values.dev.yaml 24 | LICENSE 25 | README.md -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Mono auto generated files 17 | mono_crash.* 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | [Ww][Ii][Nn]32/ 27 | [Aa][Rr][Mm]/ 28 | [Aa][Rr][Mm]64/ 29 | bld/ 30 | [Bb]in/ 31 | [Oo]bj/ 32 | [Ll]og/ 33 | [Ll]ogs/ 34 | 35 | # Visual Studio 2015/2017 cache/options directory 36 | .vs/ 37 | # Uncomment if you have tasks that create the project's static files in wwwroot 38 | #wwwroot/ 39 | 40 | # Visual Studio 2017 auto generated files 41 | Generated\ Files/ 42 | 43 | # MSTest test Results 44 | [Tt]est[Rr]esult*/ 45 | [Bb]uild[Ll]og.* 46 | 47 | # NUnit 48 | *.VisualState.xml 49 | TestResult.xml 50 | nunit-*.xml 51 | 52 | # Build Results of an ATL Project 53 | [Dd]ebugPS/ 54 | [Rr]eleasePS/ 55 | dlldata.c 56 | 57 | # Benchmark Results 58 | BenchmarkDotNet.Artifacts/ 59 | 60 | # .NET Core 61 | project.lock.json 62 | project.fragment.lock.json 63 | artifacts/ 64 | 65 | # Tye 66 | .tye/ 67 | 68 | # ASP.NET Scaffolding 69 | ScaffoldingReadMe.txt 70 | 71 | # StyleCop 72 | StyleCopReport.xml 73 | 74 | # Files built by Visual Studio 75 | *_i.c 76 | *_p.c 77 | *_h.h 78 | *.ilk 79 | *.meta 80 | *.obj 81 | *.iobj 82 | *.pch 83 | *.pdb 84 | *.ipdb 85 | *.pgc 86 | *.pgd 87 | *.rsp 88 | *.sbr 89 | *.tlb 90 | *.tli 91 | *.tlh 92 | *.tmp 93 | *.tmp_proj 94 | *_wpftmp.csproj 95 | *.log 96 | *.vspscc 97 | *.vssscc 98 | .builds 99 | *.pidb 100 | *.svclog 101 | *.scc 102 | 103 | # Chutzpah Test files 104 | _Chutzpah* 105 | 106 | # Visual C++ cache files 107 | ipch/ 108 | *.aps 109 | *.ncb 110 | *.opendb 111 | *.opensdf 112 | *.sdf 113 | *.cachefile 114 | *.VC.db 115 | *.VC.VC.opendb 116 | 117 | # Visual Studio profiler 118 | *.psess 119 | *.vsp 120 | *.vspx 121 | *.sap 122 | 123 | # Visual Studio Trace Files 124 | *.e2e 125 | 126 | # TFS 2012 Local Workspace 127 | $tf/ 128 | 129 | # Guidance Automation Toolkit 130 | *.gpState 131 | 132 | # ReSharper is a .NET coding add-in 133 | _ReSharper*/ 134 | *.[Rr]e[Ss]harper 135 | *.DotSettings.user 136 | 137 | # TeamCity is a build add-in 138 | _TeamCity* 139 | 140 | # DotCover is a Code Coverage Tool 141 | *.dotCover 142 | 143 | # AxoCover is a Code Coverage Tool 144 | .axoCover/* 145 | !.axoCover/settings.json 146 | 147 | # Coverlet is a free, cross platform Code Coverage Tool 148 | coverage*.json 149 | coverage*.xml 150 | coverage*.info 151 | 152 | # Visual Studio code coverage results 153 | *.coverage 154 | *.coveragexml 155 | 156 | # NCrunch 157 | _NCrunch_* 158 | .*crunch*.local.xml 159 | nCrunchTemp_* 160 | 161 | # MightyMoose 162 | *.mm.* 163 | AutoTest.Net/ 164 | 165 | # Web workbench (sass) 166 | .sass-cache/ 167 | 168 | # Installshield output folder 169 | [Ee]xpress/ 170 | 171 | # DocProject is a documentation generator add-in 172 | DocProject/buildhelp/ 173 | DocProject/Help/*.HxT 174 | DocProject/Help/*.HxC 175 | DocProject/Help/*.hhc 176 | DocProject/Help/*.hhk 177 | DocProject/Help/*.hhp 178 | DocProject/Help/Html2 179 | DocProject/Help/html 180 | 181 | # Click-Once directory 182 | publish/ 183 | 184 | # Publish Web Output 185 | *.[Pp]ublish.xml 186 | *.azurePubxml 187 | # Note: Comment the next line if you want to checkin your web deploy settings, 188 | # but database connection strings (with potential passwords) will be unencrypted 189 | *.pubxml 190 | *.publishproj 191 | 192 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 193 | # checkin your Azure Web App publish settings, but sensitive information contained 194 | # in these scripts will be unencrypted 195 | PublishScripts/ 196 | 197 | # NuGet Packages 198 | *.nupkg 199 | # NuGet Symbol Packages 200 | *.snupkg 201 | # The packages folder can be ignored because of Package Restore 202 | **/[Pp]ackages/* 203 | # except build/, which is used as an MSBuild target. 204 | !**/[Pp]ackages/build/ 205 | # Uncomment if necessary however generally it will be regenerated when needed 206 | #!**/[Pp]ackages/repositories.config 207 | # NuGet v3's project.json files produces more ignorable files 208 | *.nuget.props 209 | *.nuget.targets 210 | 211 | # Microsoft Azure Build Output 212 | csx/ 213 | *.build.csdef 214 | 215 | # Microsoft Azure Emulator 216 | ecf/ 217 | rcf/ 218 | 219 | # Windows Store app package directories and files 220 | AppPackages/ 221 | BundleArtifacts/ 222 | Package.StoreAssociation.xml 223 | _pkginfo.txt 224 | *.appx 225 | *.appxbundle 226 | *.appxupload 227 | 228 | # Visual Studio cache files 229 | # files ending in .cache can be ignored 230 | *.[Cc]ache 231 | # but keep track of directories ending in .cache 232 | !?*.[Cc]ache/ 233 | 234 | # Others 235 | ClientBin/ 236 | ~$* 237 | *~ 238 | *.dbmdl 239 | *.dbproj.schemaview 240 | *.jfm 241 | *.pfx 242 | *.publishsettings 243 | orleans.codegen.cs 244 | 245 | # Including strong name files can present a security risk 246 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 247 | #*.snk 248 | 249 | # Since there are multiple workflows, uncomment next line to ignore bower_components 250 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 251 | #bower_components/ 252 | 253 | # RIA/Silverlight projects 254 | Generated_Code/ 255 | 256 | # Backup & report files from converting an old project file 257 | # to a newer Visual Studio version. Backup files are not needed, 258 | # because we have git ;-) 259 | _UpgradeReport_Files/ 260 | Backup*/ 261 | UpgradeLog*.XML 262 | UpgradeLog*.htm 263 | ServiceFabricBackup/ 264 | *.rptproj.bak 265 | 266 | # SQL Server files 267 | *.mdf 268 | *.ldf 269 | *.ndf 270 | 271 | # Business Intelligence projects 272 | *.rdl.data 273 | *.bim.layout 274 | *.bim_*.settings 275 | *.rptproj.rsuser 276 | *- [Bb]ackup.rdl 277 | *- [Bb]ackup ([0-9]).rdl 278 | *- [Bb]ackup ([0-9][0-9]).rdl 279 | 280 | # Microsoft Fakes 281 | FakesAssemblies/ 282 | 283 | # GhostDoc plugin setting file 284 | *.GhostDoc.xml 285 | 286 | # Node.js Tools for Visual Studio 287 | .ntvs_analysis.dat 288 | node_modules/ 289 | 290 | # Visual Studio 6 build log 291 | *.plg 292 | 293 | # Visual Studio 6 workspace options file 294 | *.opt 295 | 296 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 297 | *.vbw 298 | 299 | # Visual Studio LightSwitch build output 300 | **/*.HTMLClient/GeneratedArtifacts 301 | **/*.DesktopClient/GeneratedArtifacts 302 | **/*.DesktopClient/ModelManifest.xml 303 | **/*.Server/GeneratedArtifacts 304 | **/*.Server/ModelManifest.xml 305 | _Pvt_Extensions 306 | 307 | # Paket dependency manager 308 | .paket/paket.exe 309 | paket-files/ 310 | 311 | # FAKE - F# Make 312 | .fake/ 313 | 314 | # CodeRush personal settings 315 | .cr/personal 316 | 317 | # Python Tools for Visual Studio (PTVS) 318 | __pycache__/ 319 | *.pyc 320 | 321 | # Cake - Uncomment if you are using it 322 | # tools/** 323 | # !tools/packages.config 324 | 325 | # Tabs Studio 326 | *.tss 327 | 328 | # Telerik's JustMock configuration file 329 | *.jmconfig 330 | 331 | # BizTalk build output 332 | *.btp.cs 333 | *.btm.cs 334 | *.odx.cs 335 | *.xsd.cs 336 | 337 | # OpenCover UI analysis results 338 | OpenCover/ 339 | 340 | # Azure Stream Analytics local run output 341 | ASALocalRun/ 342 | 343 | # MSBuild Binary and Structured Log 344 | *.binlog 345 | 346 | # NVidia Nsight GPU debugger configuration file 347 | *.nvuser 348 | 349 | # MFractors (Xamarin productivity tool) working folder 350 | .mfractor/ 351 | 352 | # Local History for Visual Studio 353 | .localhistory/ 354 | 355 | # BeatPulse healthcheck temp database 356 | healthchecksdb 357 | 358 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 359 | MigrationBackup/ 360 | 361 | # Ionide (cross platform F# VS Code tools) working folder 362 | .ionide/ 363 | 364 | # Fody - auto-generated XML schema 365 | FodyWeavers.xsd 366 | 367 | ## 368 | ## Visual studio for Mac 369 | ## 370 | 371 | 372 | # globs 373 | Makefile.in 374 | *.userprefs 375 | *.usertasks 376 | config.make 377 | config.status 378 | aclocal.m4 379 | install-sh 380 | autom4te.cache/ 381 | *.tar.gz 382 | tarballs/ 383 | test-results/ 384 | 385 | # Mac bundle stuff 386 | *.dmg 387 | *.app 388 | 389 | # content below from: https://github.com/github/gitignore/blob/master/Global/macOS.gitignore 390 | # General 391 | .DS_Store 392 | .AppleDouble 393 | .LSOverride 394 | 395 | # Icon must end with two \r 396 | Icon 397 | 398 | 399 | # Thumbnails 400 | ._* 401 | 402 | # Files that might appear in the root of a volume 403 | .DocumentRevisions-V100 404 | .fseventsd 405 | .Spotlight-V100 406 | .TemporaryItems 407 | .Trashes 408 | .VolumeIcon.icns 409 | .com.apple.timemachine.donotpresent 410 | 411 | # Directories potentially created on remote AFP share 412 | .AppleDB 413 | .AppleDesktop 414 | Network Trash Folder 415 | Temporary Items 416 | .apdisk 417 | 418 | # content below from: https://github.com/github/gitignore/blob/master/Global/Windows.gitignore 419 | # Windows thumbnail cache files 420 | Thumbs.db 421 | ehthumbs.db 422 | ehthumbs_vista.db 423 | 424 | # Dump file 425 | *.stackdump 426 | 427 | # Folder config file 428 | [Dd]esktop.ini 429 | 430 | # Recycle Bin used on file shares 431 | $RECYCLE.BIN/ 432 | 433 | # Windows Installer files 434 | *.cab 435 | *.msi 436 | *.msix 437 | *.msm 438 | *.msp 439 | 440 | # Windows shortcuts 441 | *.lnk 442 | 443 | # JetBrains Rider 444 | .idea/ 445 | *.sln.iml 446 | 447 | ## 448 | ## Visual Studio Code 449 | ## 450 | .vscode/* 451 | !.vscode/settings.json 452 | !.vscode/tasks.json 453 | !.vscode/launch.json 454 | !.vscode/extensions.json 455 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Microsoft Open Source Code of Conduct 2 | 3 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 4 | 5 | Resources: 6 | 7 | - [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/) 8 | - [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) 9 | - Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns 10 | -------------------------------------------------------------------------------- /HandsOn.md: -------------------------------------------------------------------------------- 1 | # How to use CosmosDB Helper Library 2 | 3 | >You need to have Azure subscription and provisioned Azure Cosmos DB (SQL API or MongoDB API). 4 | > 5 | >Let's start it with Azure Cosmos DB with SQL API first (You may easily shift it for Mongo API later) 6 | 7 | 8 | 9 | ## Work with SQL API (Azure Cosmos DB SDK) 10 | 11 | ### 0. Pre-requisites 12 | 13 | - We need to prepare Azure CosmosDB resource before starting it. 14 | 15 | I assume you have Azure CosmosDB SQL API instance and CosmosDB Mongo API instance both. 16 | If you don't have it, please prepare your CosmosDB resources. Here is the link [how to provision your Cosmos DB resources from Azure Portal](https://docs.microsoft.com/en-us/azure/cosmos-db/create-cosmosdb-resources-portal) 17 | 18 | Please make sure which API are you working with. 19 | 20 | 21 | - .NET Framework 5.0 22 | 23 | The Cosmos DB Helper libraries has been compiled with .NET Framework 5.0 24 | Before starting it, you need to install .NET Framework 5.0 in your development environment. 25 | If you don't have it, please install it from here - [.NET Framework 5.0 SDK Download](https://dotnet.microsoft.com/download/dotnet/thank-you/sdk-5.0.100-windows-x64-installer) 26 | 27 | If you tried to load the solution file with your Visual Studio 2019 without installing .NET Framework 5.0, 28 | You might get following error : 29 | 30 | >\Program Files\dotnet\sdk\3.1.201\Microsoft.Common.CurrentVersion.targets(1177,5): error MSB3644: 31 | >The reference assemblies for .NETFramework,Version=v5.0 were not found. 32 | >To resolve this, install the Developer Pack (SDK/Targeting Pack) for this framework version or retarget your application. 33 | >You can download .NET Framework Developer Packs at https://aka.ms/msbuild/developerpacks 34 | 35 | Unfortunately this link doesn't point .NET Framework version 5, only 4.8 now. 36 | To download version 5, you can download it from here [https://dotnet.microsoft.com/download/visual-studio-sdks](https://dotnet.microsoft.com/download/visual-studio-sdks) 37 | and I do recommend you upgrade your Visual Studio version up to 16.8.x. 38 | 39 | 40 | - VS Code 41 | 42 | It's OK to start with Visual Studio 2019 but I'm going to start with VS Code in this hands on. 43 | If you don't have it, you may download it from here - [Download VSCode](https://code.visualstudio.com/) 44 | 45 | 46 | ### 1. Create Project 47 | Please make sure all of pre-requisites are all set. 48 | Let's start hands on for now! 49 | 50 | Create Console project from Console Window 51 | 52 | ``` 53 | 54 | dotnet new console -n CosmosHandsOn --framework net5.0 55 | 56 | ``` 57 | 58 | 59 | 60 | After creating Console project name CosmosHandsOn, Switch the directory to newly created project. 61 | 62 | ``` 63 | 64 | cd CosmosHandsOn 65 | 66 | ``` 67 | 68 | ### 2. Add Reference CosmosDB Helper 69 | After switching the directory, add package Reference with Nuget installation 70 | 71 | ``` 72 | 73 | dotnet add package EAE.Solutions.CosmosDB.SQL --version 0.7.3 74 | 75 | ``` 76 | 77 | 78 | 79 | ### 3. Define Entity Class 80 | After referencing CosmosDB Helper, let's define Entity Class will be stored in CosmosDB 81 | 82 | Open your VS Code with this command 83 | 84 | ``` 85 | 86 | code . 87 | 88 | ``` 89 | 90 | then Add Entity Class with name **ToDo.cs** 91 | 92 | 93 | 94 | Define ToDo class with inheriting CosmosDBEntityBase in Microsoft.Solutions.CosmosDB Namespace. 95 | CosmosDBEntityBase class has responsibility for managing Entity's ID and PartitionKey which may effect to retrieving performance in the cosmos DB. 96 | 97 | ```csharp 98 | 99 | using System; 100 | using Microsoft.Solutions.CosmosDB; 101 | namespace CosmosHandsOn 102 | { 103 | public class ToDo : CosmosDBEntityBase 104 | { 105 | public string title { get; set; } 106 | public Status status { get; set; } 107 | public DateTime startDate { get; set; } 108 | public DateTime endDate { get; set; } 109 | public string notes { get; set; } 110 | 111 | private int _percentComplete; 112 | 113 | public int percentComplete 114 | { 115 | get { return _percentComplete; } 116 | set 117 | { 118 | if ((percentComplete < 0) || (percentComplete > 100)) 119 | { 120 | throw new OverflowException("percent value should be between 0 to 100"); 121 | } 122 | else 123 | { 124 | _percentComplete = percentComplete; 125 | } 126 | } 127 | } 128 | } 129 | 130 | public enum Status { New, InProcess, Done } 131 | } 132 | 133 | ``` 134 | 135 | ### 4. Define Entity Collection Class 136 | Now add new EntityCollectionBase Class with name **ToDoService.cs** 137 | 138 | EntityCollectionBase class is managing Connection Objects and CRUD operations for CosmosDBEntityBase class objects 139 | 140 | 141 | 142 | Define ToDoService class with inheriting SQLEntityCollectionBase which is EntityCollectionBase class for SQL API and specify Entity Class types will manage. 143 | 144 | Once you inherit SQLEntityCollectionBase class, you should generate constructor which has 2 parameters for Database ConnectionString and Database Name. 145 | 146 | The 2 constructor parameters supposed to be passed to SQLEntityCollectionBase class for managing Azure CosmosDB connection and Entity object collection(container). 147 | 148 | ```csharp 149 | 150 | using System; 151 | using Microsoft.Solutions.CosmosDB.SQL; 152 | 153 | namespace CosmosHandsOn{ 154 | public class ToDoService : SQLEntityCollectionBase 155 | { 156 | public ToDoService(string DataConnectionString, string CollectionName) : base(DataConnectionString, CollectionName) 157 | { 158 | } 159 | } 160 | } 161 | 162 | ``` 163 | 164 | 165 | 166 | SQLEntityCollectionBase class provides features for Azure CosmosDB SQL API CRUD operations internally. 167 | Let's define CRUD operations in ToDoService. 168 | 169 | SQLEntityCollectionBase Class has EntityCollection property. 170 | You can operate(Crate, Replace, Update, Delete) Azure CosmosDB with your own Business Entities with it. 171 | 172 | Below is the CRUD operations you may easily interact with Azure CosmosDB 173 | 174 | - AddAsync method in EntityCollection can insert your object in CosmosDB 175 | 176 | ```csharp 177 | 178 | public async Task Create(ToDo todo) 179 | { 180 | return await this.EntityCollection.AddAsync(todo); 181 | } 182 | 183 | ``` 184 | 185 | - SaveAsync method in EntityCollection can update your object in CosmosDB. 186 | 187 | ```csharp 188 | 189 | public async Task Update(ToDo todo) 190 | { 191 | return await this.EntityCollection.SaveAsync(todo); 192 | } 193 | 194 | ``` 195 | 196 | - Get method in EntityCollection can retrieve Entity with Entity's id.(The Entity's identifier which will be managing by CosmosDB Helper class) 197 | 198 | ```csharp 199 | 200 | public async Task Find(string id) 201 | { 202 | return await this.EntityCollection.GetAsync(id); 203 | } 204 | 205 | ``` 206 | 207 | - FindAllAsync method in EntityCollection can retrieve Entities with LINQ statements. 208 | 209 | ```csharp 210 | 211 | public async Task> Search(string notes) 212 | { 213 | return await this.EntityCollection.FindAllAsync(new GenericSpecification(x => x.notes.Contains(notes))); 214 | } 215 | 216 | ``` 217 | 218 | - DeleteAsync method in EntityCollection can delete Entity by Entity's id or Entity itself. 219 | 220 | ```csharp 221 | 222 | public async Task Delete(string id) 223 | { 224 | await this.EntityCollection.DeleteAsync(id); 225 | } 226 | 227 | ``` 228 | 229 | Done! You are ready to create, update, search and delete Entities with these simple methods. 230 | 231 | This is full ToDoServices.cs codes 232 | 233 | ```csharp 234 | 235 | using System; 236 | using System.Threading.Tasks; 237 | using System.Collections.Generic; 238 | using Microsoft.Solutions.CosmosDB; 239 | using Microsoft.Solutions.CosmosDB.SQL; 240 | 241 | namespace CosmosHandsOn{ 242 | public class ToDoService : SQLEntityCollectionBase 243 | { 244 | public ToDoService(string DataConnectionString, string CollectionName) : base(DataConnectionString, CollectionName) 245 | { 246 | //just passing constructor parameters 247 | } 248 | 249 | public async Task Create(ToDo todo) 250 | { 251 | return await this.EntityCollection.AddAsync(todo); 252 | } 253 | 254 | public async Task Update(ToDo todo) 255 | { 256 | return await this.EntityCollection.SaveAsync(todo); 257 | } 258 | 259 | public async Task Find(string id) 260 | { 261 | return await this.EntityCollection.GetAsync(id); 262 | } 263 | 264 | public async Task> Search(string notes) 265 | { 266 | return await this.EntityCollection.FindAllAsync(new GenericSpecification(x => x.notes.Contains(notes))); 267 | } 268 | 269 | public async Task Delete(string id) 270 | { 271 | await this.EntityCollection.DeleteAsync(id); 272 | } 273 | } 274 | } 275 | 276 | ``` 277 | 278 | Now you may put this ToDoService on wherever you want to host it through MicroService containers or Azure Functions. 279 | 280 | Let's try to test it with Console Application from here. 281 | 282 | Open **Programs.cs** and define CosmosDB ConnectionString. 283 | To invoking asynchronous methods we need to change **static void Main** method signature to **async static Task Main** . 284 | 285 | Please check your Azure CosmosDB connection string from Azure portal and copy & paste it like below. 286 | 287 | ```csharp 288 | 289 | using System; 290 | using System.Threading.Tasks; 291 | 292 | namespace CosmosHandsOn 293 | { 294 | class Program 295 | { 296 | static string connectionString = "{Put your connectionstring}"; 297 | 298 | async static Task Main(string[] args) 299 | { 300 | } 301 | } 302 | } 303 | 304 | ``` 305 | 306 | And instantiate ToDoService with connection string and Database name together. 307 | The SQLEntityCollectionBase which has been inherited by ToDoService is going to check existence of Database and once it is not exiting, it will generate Database automatically on the fly. 308 | 309 | Put this code for instancing ToDoService like below 310 | 311 | ```csharp 312 | 313 | async static Task Main(string[] args) 314 | { 315 | var todoService = new ToDoService(connectionString, "CosmosHandson"); 316 | } 317 | 318 | ``` 319 | 320 | It will create CosmosHandson Database in your Azure CosmosDB. 321 | Now add the codes for testing ToDoService with this codes 322 | 323 | Create ToDo object like below. 324 | 325 | ```csharp 326 | 327 | 328 | var todo = new ToDo() 329 | { 330 | title = "This is test ToDo", 331 | startDate = DateTime.Now, 332 | endDate = DateTime.Now.AddDays(2), 333 | percentComplete = 0, 334 | notes = "Cosmos DB is really cool!", 335 | status = Status.New 336 | }; 337 | 338 | ``` 339 | 340 | You might be acknowledged that ToDo class has id and __partitionkey properties natively. 341 | You don't necessary to touch them from your code. the id and _partitionkey will be managed by CosmosDB Helper by itself. 342 | 343 | After instancing ToDo class let's add the codes following. 344 | 345 | ```csharp 346 | 347 | using System; 348 | using System.Threading.Tasks; 349 | 350 | namespace CosmosHandsOn 351 | { 352 | class Program 353 | { 354 | static string connectionString = "{Put your connectionstring}"; 355 | 356 | async static Task Main(string[] args) 357 | { 358 | var todoService = new ToDoService(connectionString, "CosmosHandson"); 359 | 360 | var todo = new ToDo() 361 | { 362 | title = "This is test ToDo", 363 | startDate = DateTime.Now, 364 | endDate = DateTime.Now.AddDays(2), 365 | percentComplete = 0, 366 | notes = "Cosmos DB is really cool!", 367 | status = Status.New 368 | }; 369 | 370 | //Insert ToDO 371 | var objTodo1 = await todoService.Create(todo); 372 | 373 | //Update ToDo 374 | objTodo1.title = "Updating test ToDo"; 375 | await todoService.Update(objTodo1); 376 | 377 | //Search ToDo 378 | var objRetrived = await todoService.Find(objTodo1.id); 379 | Console.WriteLine($"Found object! it's title is {objRetrived.title}"); 380 | 381 | //Find ToDos 382 | var todos = await todoService.Search("Cosmos"); 383 | foreach (var item in todos) 384 | { 385 | Console.WriteLine($"{item.id} - {item.title} - {item.notes} - {item.status}"); 386 | } 387 | 388 | //Delete ToDos 389 | await todoService.Delete(objTodo1.id); 390 | Console.WriteLine($"The Todo object which has title - {objTodo1.title} has been removed"); 391 | } 392 | } 393 | } 394 | 395 | ``` 396 | 397 | and Execute the code with pressing F5(Debugging) or CTRL + F5(Execute without Debugging) 398 | You may check every CRUD operations are working perfectly. 399 | 400 | 401 | 402 | It's time to use Azure CosmosDB Mongo API Service with our code. 403 | 404 |

405 | 406 | --- 407 | 408 |

409 | ## Work with Cosmos DB for Mongo API 410 | >It's easy! We've already implemented all CRUD operations in ToDoService class. 411 | Azure Cosmos DBHelper provides exactly same development experience with previous one what we did. 412 | > 413 | >To start with Azure CosmosDB for Mongo API, You need to prepare Azure CosmosDB for Mongo API instance. 414 | If You don't have it yet, deploy Azure CosmosDB for MongoDB like blow before moving further. 415 | > 416 | > 417 | > 418 | >After provisioning Azure CosmosDB for Mongo API, grep the connection string. 419 | >The Connection string format for Mongo is different with Azure CosmosDB for SQL API. 420 | 421 | ### 1. Add Reference 422 | 423 | Try to Add Azure CosmosDB mongo Helper library with nuget package reference in your source directory like below 424 | 425 | ``` 426 | 427 | dotnet add package EAE.Solutions.CosmosDB.Mongo --version 0.7.3 428 | 429 | ``` 430 | 431 | 432 | 433 | 434 | ### 2. Inherit MongoEntityCollectionBase in ToDoService 435 | Open the VS Code again from the source folder. 436 | 437 | ``` 438 | 439 | code . 440 | 441 | ``` 442 | 443 | In previous code, ToDoService inherited SQLEntityCollectionBase. 444 | Just replace ToDoService's base class with **MongoEntityCollectionBase** and replace **using Microsoft.Solutions.CosmosDB.SQL** namespace to **Microsoft.Solutions.CosmosDB.Mongo**. 445 | 446 | ```csharp 447 | using System; 448 | using Microsoft.Solutions.CosmosDB.Mongo; 449 | using System.Threading.Tasks; 450 | using System.Collections.Generic; 451 | using Microsoft.Solutions.CosmosDB; 452 | 453 | namespace CosmosHandsOn{ 454 | public class ToDoService : MongoEntntyCollectionBase 455 | { 456 | public ToDoService(string DataConnectionString, string CollectionName) : base(DataConnectionString, CollectionName) 457 | { 458 | } 459 | 460 | public async Task Create(ToDo todo) 461 | { 462 | return await this.EntityCollection.AddAsync(todo); 463 | } 464 | 465 | public async Task Update(ToDo todo) 466 | { 467 | return await this.EntityCollection.SaveAsync(todo); 468 | } 469 | 470 | public async Task Find(string id) 471 | { 472 | return await this.EntityCollection.GetAsync(id); 473 | } 474 | 475 | public async Task> Search(string notes) 476 | { 477 | return await this.EntityCollection.FindAllAsync(new GenericSpecification(x => x.notes.Contains(notes))); 478 | } 479 | 480 | public async Task Delete(string id) 481 | { 482 | await this.EntityCollection.DeleteAsync(id); 483 | } 484 | 485 | } 486 | } 487 | ``` 488 | 489 | ### 3. Update ConnectionString 490 | > Don't forget to update your connection string for MongoDB in programs.cs file! 491 | 492 | That's all we should do to switch our code for using CosmosDB Mongo API. 493 | Just Execute the code with pressing F5(Debugging) or CTRL + F5(Execute without Debugging) 494 | 495 | 496 | ## Dependency Injection in ASP.net 497 | 498 | All of CosmosDB Helper is sharing [IDataRepositoryProvider](./src/Libraries/Microsoft.CosmosDB/../Microsoft.Solutions.CosmosDB/IDataRepositoryProvider.cs) interface. 499 | 500 | ```csharp 501 | 502 | namespace Microsoft.Solutions.CosmosDB 503 | { 504 | public interface IDataRepositoryProvider 505 | { 506 | IRepository EntityCollection { get; init ; } 507 | } 508 | } 509 | 510 | ``` 511 | 512 | so you may inject your dependency with this interface. 513 | 514 | This is the sample code snippet for showing how to inject dependency into DoToService. 515 | 516 | ```csharp 517 | 518 | services.AddTransient, TODOService>(x => { return new TODOService(configuration["ConnectionString"], "CosmosHandson"); }); 519 | 520 | ``` 521 | 522 | You may check the ToDo ASP.net API sample project from [here](../../tree/main/src/Sample/Microsoft.Solutions.CosmosDB.WebHost) 523 | 524 | ## Working in Visual Studio 2019 or 2017 525 | Absolutely Visual Studio is the first citizen .NET Development. 526 | If you want to start hands on from .NET Framework, you may reference proper package with Nuget Package manager. 527 | 528 | 529 | 530 | 531 | ## EAE.Solutions.CosmosDB.SQL.ChangeFeed - Change feed Processor Helper 532 | > Currently it supports **SQL Core API only**, EAE.Solutions.CosmosDB.MongoDB.ChangeFeed will be released next version. 533 | 534 | 535 | The change feed processor is part of the Azure Cosmos DB SDK V3. 536 | **Watcher** class in Microsoft.Solutions.CosmosDB.SQL.ChangeFeed namespace derived from BackgroundService, which supports hosting and managing Change feed processors as well as handle change entity collections. 537 | 538 | Just Passing monitored entity collections(container) name as parameter to Watcher class then you can catch the changed entity sets. 539 | 540 | We can host Watcher on .NET Generic Host in ASP.net core - https://docs.microsoft.com/en-us/dotnet/architecture/microservices/multi-container-microservice-net-applications/background-tasks-with-ihostedservice 541 | 542 | See the Sample Application for Azure CosmosDB Change feed host [here](./Sample/Microsoft.Solutions.CosmosDB.SQL.ChangeFeed.Service) 543 | 544 | ```csharp 545 | 546 | using Microsoft.Extensions.Configuration; 547 | using Microsoft.Solutions.CosmosDB.SQL.ChangeFeed; 548 | using Microsoft.Solutions.CosmosDB.SQL.ChangeFeed.Service.Models; 549 | using Newtonsoft.Json; 550 | using System; 551 | using System.Collections.Generic; 552 | using System.Threading; 553 | using System.Threading.Tasks; 554 | 555 | namespace Microsoft.Solutions.CosmosDB.SQL.TODO.ChangeFeed.Service 556 | { 557 | public class Worker : Watcher 558 | { 559 | /// 560 | /// Passing configuration by ASPnet core Dependency Injection 561 | /// This Application sample shows how to detact changes for TODO collection by Microsoft.Solutions.CosmosDB.SQL.TODO.WebHost Demo App 562 | /// 563 | /// Check appsettings.json file definition 564 | public Worker(IConfiguration configuration) : base(configuration["Values:DBConnectionString"], 565 | configuration["Values:MonitoredDatabaseName"], 566 | configuration["Values:MonitoredContainerName"]) 567 | { 568 | } 569 | 570 | protected override Task OnChangedFeedDataSets(IReadOnlyCollection changes, CancellationToken cancellationToken) 571 | { 572 | //put your business logics with changes 573 | foreach (var item in changes) 574 | { 575 | Console.WriteLine($"Detected operation for item with id {item.id} => {JsonConvert.SerializeObject(item)}"); 576 | } 577 | 578 | return base.OnChangedFeedDataSets(changes, cancellationToken); 579 | } 580 | } 581 | } 582 | 583 | 584 | ``` 585 | 586 | Now, Let's make our hands dirt by creating Change Feed Process Host for DoTo Entity Container what we tested in previous handson with Watcher class. 587 | 588 | ### 1. Create Project 589 | Create Worker Service project from Console Window. 590 | dotnet CLI tool provides [Worker Service host project template](https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-new-sdk-templates#web-others). 591 | 592 | Type dotnet CLI command like below in your Console. 593 | 594 | ``` 595 | 596 | dotnet new worker -n CosmosHandsOnChangeFeed --framework net5.0 597 | 598 | ``` 599 | 600 | 601 | 602 | After creating project template, move the directory path to CosmosHandsOnChangeFeed 603 | 604 | ``` 605 | cd .\CosmosHandsOnChangeFeed 606 | 607 | ``` 608 | ### 2. Add Reference CosmosDB Helper 609 | After switching the directory, add package Reference with Nuget installation. 610 | This Nuget package contains Watcher class in Microsoft.Solutions.CosmosDB.SQL.ChangeFeed Namespace 611 | 612 | ``` 613 | 614 | dotnet add package EAE.Solutions.CosmosDB.SQL.ChangeFeed --version 0.7.3 615 | 616 | ``` 617 | 618 | 619 | 620 | Then Open VSCode 621 | 622 | ``` 623 | 624 | code . 625 | 626 | ``` 627 | 628 | You may check the .NET Generic Host ASP.net core project scarffolding source files. 629 | 630 | 631 | 632 | ### 3. Add ToDo Entity class 633 | Now we are going to add Entity Class where Monitored Container has. 634 | We are going to watch ToDos Container what we created in previous handson. 635 | 636 | Add new file with ToDo.cs and Copy below code and paste to ToDo.cs file 637 | 638 | ```csharp 639 | 640 | using System; 641 | using Microsoft.Solutions.CosmosDB; 642 | namespace CosmosHandsOnChangeFeed 643 | { 644 | public class ToDo : CosmosDBEntityBase 645 | { 646 | public string title { get; set; } 647 | public Status status { get; set; } 648 | public DateTime startDate { get; set; } 649 | public DateTime endDate { get; set; } 650 | public string notes { get; set; } 651 | 652 | private int _percentComplete; 653 | 654 | public int percentComplete 655 | { 656 | get { return _percentComplete; } 657 | set 658 | { 659 | if ((percentComplete < 0) || (percentComplete > 100)) 660 | { 661 | throw new OverflowException("percent value should be between 0 to 100"); 662 | } 663 | else 664 | { 665 | _percentComplete = percentComplete; 666 | } 667 | } 668 | } 669 | } 670 | 671 | public enum Status { New, InProcess, Done } 672 | } 673 | 674 | ``` 675 | ### 4. Inherit Watcher Class in EAE.Solutions.CosmosDB.SQL.ChangeFeed 676 | 677 | We have prepared ToDo EntityClass for monitoring entity container. 678 | Now let's set up Watcher class to minitoring ToDos container. 679 | 680 | Open Worker.cs file 681 | 682 | ``` csharp 683 | using System; 684 | using System.Collections.Generic; 685 | using System.Linq; 686 | using System.Threading; 687 | using System.Threading.Tasks; 688 | using Microsoft.Extensions.Hosting; 689 | using Microsoft.Extensions.Logging; 690 | 691 | namespace CosmosHandsOnChangeFeed 692 | { 693 | public class Worker : BackgroundService 694 | { 695 | private readonly ILogger _logger; 696 | 697 | public Worker(ILogger logger) 698 | { 699 | _logger = logger; 700 | } 701 | 702 | protected override async Task ExecuteAsync(CancellationToken stoppingToken) 703 | { 704 | while (!stoppingToken.IsCancellationRequested) 705 | { 706 | _logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now); 707 | await Task.Delay(1000, stoppingToken); 708 | } 709 | } 710 | } 711 | } 712 | ``` 713 | 714 | There are some sample codes for BackgroundService. 715 | Add ```Microsoft.Solutions.CosmosDB.SQL.ChangeFeed``` Namespace and then change its Base Class from ```BackgroundService``` to ```Watcher```. 716 | Then remove whole codes in Worker class like below. 717 | 718 | ```csharp 719 | 720 | using System; 721 | using System.Collections.Generic; 722 | using System.Linq; 723 | using System.Threading; 724 | using System.Threading.Tasks; 725 | using Microsoft.Extensions.Hosting; 726 | using Microsoft.Extensions.Logging; 727 | using Microsoft.Solutions.CosmosDB.SQL.ChangeFeed; 728 | 729 | namespace CosmosHandsOnChangeFeed 730 | { 731 | public class Worker : Watcher 732 | { 733 | 734 | 735 | } 736 | } 737 | 738 | ``` 739 | 740 | Now Add Constructor with IConfiguration Dependency Injection and Pass 3 parameter to its Base class like below. 741 | 742 | the 3 parameters supposed to be passed to Base class is Azure CosmosDB Connectionstring and Monitored Database and Container name. 743 | We are going to update parameter information in appsettings.json file. 744 | 745 | ASPnet core has its native Dependency Injection framework and it will read appsettings.json file then pass to every hosted instances at its constructor. 746 | 747 | ```csharp 748 | 749 | public class Worker : Watcher 750 | { 751 | public Worker(IConfiguration configuration ) : base(configuration["Values:DBConnectionString"], 752 | configuration["Values:MonitoredDatabaseName"], 753 | configuration["Values:MonitoredContainerName"]) 754 | { 755 | } 756 | } 757 | 758 | ``` 759 | ### 5. Override OnChangeFeedDataSets 760 | 761 | Now Override ```OnChangeFeedDataSets``` from its Base class like below 762 | 763 | 764 | 765 | ```csharp 766 | 767 | protected override Task OnChangedFeedDataSets(IReadOnlyCollection changes, CancellationToken cancellationToken) 768 | { 769 | return base.OnChangedFeedDataSets(changes, cancellationToken); 770 | } 771 | 772 | ``` 773 | 774 | Whenever Monitored Entity Container updated, The Watcher will catch them with ``IReadOnlyCollection`` changes parameter. 775 | 776 | Just add the code for Printing out changes into Console window like below: 777 | 778 | ```csharp 779 | protected override Task OnChangedFeedDataSets(IReadOnlyCollection changes, CancellationToken cancellationToken) 780 | { 781 | foreach (var item in changes) 782 | { 783 | Console.WriteLine($"Changed ToDo => Title : {item.title} /n Status : {item.status} / Notes : {item.notes} "); 784 | } 785 | 786 | return base.OnChangedFeedDataSets(changes, cancellationToken); 787 | } 788 | ``` 789 | 790 | You can add your own business logics in here instead of Console print out at your requirements. 791 | 792 | Here is the whole Worker.cs codes : 793 | 794 | ```csharp 795 | using System; 796 | using System.Collections.Generic; 797 | using System.Threading; 798 | using System.Threading.Tasks; 799 | using Microsoft.Extensions.Configuration; 800 | using Microsoft.Solutions.CosmosDB.SQL.ChangeFeed; 801 | 802 | namespace CosmosHandsOnChangeFeed 803 | { 804 | public class Worker : Watcher 805 | { 806 | public Worker(IConfiguration configuration ) : base(configuration["Values:DBConnectionString"], 807 | configuration["Values:MonitoredDatabaseName"], 808 | configuration["Values:MonitoredContainerName"]) 809 | { 810 | } 811 | 812 | protected override Task OnChangedFeedDataSets(IReadOnlyCollection changes, CancellationToken cancellationToken) 813 | { 814 | foreach (var item in changes) 815 | { 816 | Console.WriteLine($"Changed ToDo => Title : {item.title} /n Status : {item.status} / Notes : {item.notes} "); 817 | } 818 | 819 | return base.OnChangedFeedDataSets(changes, cancellationToken); 820 | } 821 | 822 | } 823 | } 824 | ``` 825 | 826 | 827 | ### 6. Update Configuration for ConnectionString and Monitored Entity Container Information 828 | Open appsettings.json file and add configuration information like below : 829 | 830 | ```json 831 | { 832 | "Logging": { 833 | "LogLevel": { 834 | "Default": "Information", 835 | "Microsoft": "Warning", 836 | "Microsoft.Hosting.Lifetime": "Information" 837 | } 838 | }, 839 | "Values" : { 840 | "DBConnectionString" : "{Put Your Connectionstring}", 841 | "MonitoredDatabaseName" : "CosmosHandson", 842 | "MonitoredContainerName" : "ToDos" 843 | } 844 | } 845 | ``` 846 | 847 | Now you are all set. 848 | Whenerver ToDos entity container has been changed, you can catch them with this Worker class. 849 | You may put it on Container and scale with Kubernetes clusters. -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Microsoft Corporation. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE 22 | -------------------------------------------------------------------------------- /ManagedIdentity.md: -------------------------------------------------------------------------------- 1 | # EAE.Solutions.CosmosDB.Security.ManagedIdentity 2 | [EAE.Solutions.CosmosDB.Security.ManagedIdentity](src/libraries/Microsoft.Solutions.CosmosDB.Security.ManagedIdentity/) helps retrieve Azure Cosmos DB Connection Strings with Managed Identity Information. 3 | 4 | It may elimiate the security concerns of managing credentials/secrets and only can access Azure Cosmos DB from developer's dev environment or designated Azure subscription. 5 | 6 | Using Managed Identity you can control any Azure resources with predefined (or custom defined) RBACs. 7 | 8 | If you need to get more information about Azure Managed Identity, Please check this URL - https://docs.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/overview 9 | 10 | ## How to use EAE.Solutions.CosmosDB.Security.ManagedIdentity 11 | 12 | ### 1. Create User define Managed Identity 13 | Create User Assigned Managed Identity in your resource group 14 | ![Add User Assigned Managed Identity](media/UserAssignedManagedIdentity.png) 15 | 16 | Fill up information where it being deployed 17 | ![Create User Assigned Managed Identity](media/UserAssignedManagedIdentity2.png) 18 | 19 | After deploying User Assigned Managed Identity, Let's assign the predefined roles for Azure Cosmos DB 20 | 21 | ### 2. Add Role Assignment 22 | Select Azure role assignments in Managed Identity that you created then select **Add role assignment** on top then assign its role like below : 23 | **DocumentDB Account Contributor** can retrive Read/Write Connection String Information within designated resource group. 24 | 25 | ![assign Role](media/AddRoleAssignment.png) 26 | 27 | ### 3. Get Subscription ID, Resource Group Name and Client ID 28 | Go to **Overview** menu in your Managed Identity and grap the three information - **Subscription ID**, **Regource group Name** and **Client ID** 29 | 30 | ### 4. Get Azure Cosmos DB Connection String 31 | Install **EAE.Solutions.CosmosDB.Security.ManagedIdentity** Package in your Visual Studio or Visual Studio Code from Nuget : 32 | 33 | ``` 34 | dotnet add package EAE.Solutions.CosmosDB.Security.ManagedIdentity --version 0.7.3 35 | ``` 36 | 37 | Get Azure Cosmos DB Connection String like below : 38 | 39 | ``` csharp 40 | //Should install Package from Nuget (EAE.Solutions.CosmosDB.Security.ManagedIdentity) 41 | using Microsoft.Solutions.CosmosDB.Security.ManagedIdentity; 42 | 43 | //SubscriptionID, ResourceGroup Name, Cosmos DB Account Name and Managed Identity ClientID is required 44 | public async Task GetConnectionInfo(string SubscriptionId, 45 | string ResourceGroupName, 46 | string CosmosAccountName, 47 | string ManagedIdentityClientID) 48 | { 49 | return await ConnectionStringAccessor 50 | .Create(SubscriptionId, ResourceGroupName, CosmosAccountName) 51 | .GetConnectionStringsAsync(ManagedIdentityClientID); 52 | } 53 | 54 | 55 | ``` 56 | The **CosmosConnectionStrings** class contains 4 connection strings - Primary/Secondary Read,Write ConnectionStrings and Primary/Seconday ReadOnly Connection strings. You may choose one of them at your preference. 57 | 58 | ```csharp 59 | public class CosmosConnectionStrings 60 | { 61 | public string PrimaryReadWriteKey { get; set; } 62 | public string SecondaryReadWriteKey { get; set; } 63 | public string PrimaryReadOnlyKey { get; set; } 64 | public string SecondaryReadOnlyKey { get; set; } 65 | } 66 | ``` 67 | 68 | You may check the [Sample Application code](src/Sample/Microsoft.Solutions.CosmosDB.WebHost/Startup.cs) for it from here - [Web Host Sample](src/Sample/Microsoft.Solutions.CosmosDB.WebHost) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![GitHubBanner](media/DBHelperBanner.png) 2 | ## About this repository 3 | Welcome to Azure CosmosDB Solution Accelerator (Azure CosmosDB Helper). 4 | 5 | Azure CosmosDB Helper supports MongoDB API and SQL Core API interface with LINQ statements. 6 | It abstracts how data can be persisted and retrived from Database by implmenting Repository Pattern. 7 | In Architecture perspective, it decouples the data access layer from business layer so developers can their Business Entities CRUD Operations through much streightforward way without learning specific query languages for each APIs. 8 | 9 | Once your business logic has been built with LINQ statements with Azure CosmosDB Helper, you may easily switch two APIs (SQL and Mongo) with very few code changes. 10 | 11 | ## Version History 12 | - ### v 0.7.3 Update 13 | - #### Access Azure CosmosDB with [Managed Identity](https://docs.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/overview) 14 | - [**EAE.Solutions.CosmosDB.Security.ManagedIdentity**](ManagedIdentity.md) has been released 15 | - Get rid of secrets from your configuration or source code 16 | - Retireve Azure Cosmos DB Connection Strings with Managed Identity (**DocumentDB Account Contributor Role**) 17 | - Persistent Azure resource access with single Managed Identity 18 | 19 | - ### v 0.7 Update 20 | - #### Change feed processor for Azure CosmosDB Core SQL API 21 | - **Microsoft.Solutions.CosmosDB.SQL.ChangeFeed** (ChangeFeed Processor Helper) has been released 22 | - Automatic lease container creation 23 | - Multiple process host support for parallel execution in Microservice deployment 24 | - Delegate process template for detecting ChangeSets. 25 | 26 | 27 | - #### Improved performance with optimized Connection Object 28 | 29 | - #### CosmosEntityBase Name has been changed to **CosmosDBEntityBase** 30 | - Azure CosmosDB Core SQL API EF Core Deprecated 31 | - Azure CosmosDB Provider - EF Core wrapper has been deprecated 32 | (EF Core Framework's performance issue) 33 | 34 | - ### v 0.6 First Release 35 | - #### Azure CosmosDB Core SQL API support 36 | - Azure CosmosDB SDK wrapper 37 | - Azure CosmosDB Provider - EF Core wrapper 38 | - #### Azure CosmosDB MongoDB SQL API Support 39 | - MongoDB.Driver wrapper 40 | 41 | ## Prerequisites 42 | This source code has been built with .NET framework 5.0 43 | (but you may build it with .NET Core 3.1 as well) 44 | 45 | ## Purpose 46 | CosmosDB Solution Accelerator helps developers who wants to use CosmosDB with **SIMPLE** and **DEVELOPMENT CONSISTENCY**. 47 | Developers can easily switch CosmosDB APIs between SQL API and Mongo API with little changes 48 | 49 | ## How to Work with it 50 | You may start with [HandsOn](./HandsOn.md) page. 51 | All of libraries can be referenced though [Nuget packages](https://www.nuget.org/packages?q=EAE.Solutions) to your project. 52 | 53 | ## License 54 | Copyright (c) Microsoft Corporation 55 | 56 | All rights reserved. 57 | 58 | MIT License 59 | 60 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ""Software""), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 61 | 62 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 63 | 64 | THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE 65 | 66 | ## Contributing 67 | 68 | This project welcomes contributions and suggestions. Most contributions require you to agree to a 69 | Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us 70 | the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com. 71 | 72 | When you submit a pull request, a CLA bot will automatically determine whether you need to provide 73 | a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions 74 | provided by the bot. You will only need to do this once across all repos using our CLA. 75 | 76 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 77 | For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or 78 | contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. 79 | 80 | ## Trademarks 81 | 82 | This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft 83 | trademarks or logos is subject to and must follow 84 | [Microsoft's Trademark & Brand Guidelines](https://www.microsoft.com/en-us/legal/intellectualproperty/trademarks/usage/general). 85 | Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship. 86 | Any use of third-party trademarks or logos are subject to those third-party's policies. 87 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Security 4 | 5 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/). 6 | 7 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://docs.microsoft.com/en-us/previous-versions/tn-archive/cc751383(v=technet.10)), please report it to us as described below. 8 | 9 | ## Reporting Security Issues 10 | 11 | **Please do not report security vulnerabilities through public GitHub issues.** 12 | 13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://msrc.microsoft.com/create-report). 14 | 15 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://www.microsoft.com/en-us/msrc/pgp-key-msrc). 16 | 17 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc). 18 | 19 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: 20 | 21 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) 22 | * Full paths of source file(s) related to the manifestation of the issue 23 | * The location of the affected source code (tag/branch/commit or direct URL) 24 | * Any special configuration required to reproduce the issue 25 | * Step-by-step instructions to reproduce the issue 26 | * Proof-of-concept or exploit code (if possible) 27 | * Impact of the issue, including how an attacker might exploit the issue 28 | 29 | This information will help us triage your report more quickly. 30 | 31 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://microsoft.com/msrc/bounty) page for more details about our active programs. 32 | 33 | ## Preferred Languages 34 | 35 | We prefer all communications to be in English. 36 | 37 | ## Policy 38 | 39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://www.microsoft.com/en-us/msrc/cvd). 40 | 41 | -------------------------------------------------------------------------------- /SUPPORT.md: -------------------------------------------------------------------------------- 1 | # TODO: The maintainer of this repo has not yet edited this file 2 | 3 | **REPO OWNER**: Do you want Customer Service & Support (CSS) support for this product/project? 4 | 5 | - **No CSS support:** Fill out this template with information about how to file issues and get help. 6 | - **Yes CSS support:** Fill out an intake form at [aka.ms/spot](https://aka.ms/spot). CSS will work with/help you to determine next steps. More details also available at [aka.ms/onboardsupport](https://aka.ms/onboardsupport). 7 | - **Not sure?** Fill out a SPOT intake as though the answer were "Yes". CSS will help you decide. 8 | 9 | *Then remove this first heading from this SUPPORT.MD file before publishing your repo.* 10 | 11 | # Support 12 | 13 | ## How to file issues and get help 14 | 15 | This project uses GitHub Issues to track bugs and feature requests. Please search the existing 16 | issues before filing new issues to avoid duplicates. For new issues, file your bug or 17 | feature request as a new Issue. 18 | 19 | For help and questions about using this project, please **REPO MAINTAINER: INSERT INSTRUCTIONS HERE 20 | FOR HOW TO ENGAGE REPO OWNERS OR COMMUNITY FOR HELP. COULD BE A STACK OVERFLOW TAG OR OTHER 21 | CHANNEL. WHERE WILL YOU HELP PEOPLE?**. 22 | 23 | ## Microsoft Support Policy 24 | 25 | Support for this **PROJECT or PRODUCT** is limited to the resources listed above. 26 | -------------------------------------------------------------------------------- /media/AddRoleAssignment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/CosmosDB-Solution-Accelerator-CosmosDB-Helper/9242e5f80141e6f33800cc73ee3b4f56143af76a/media/AddRoleAssignment.png -------------------------------------------------------------------------------- /media/DBHelperBanner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/CosmosDB-Solution-Accelerator-CosmosDB-Helper/9242e5f80141e6f33800cc73ee3b4f56143af76a/media/DBHelperBanner.png -------------------------------------------------------------------------------- /media/UserAssignedManagedIdentity.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/CosmosDB-Solution-Accelerator-CosmosDB-Helper/9242e5f80141e6f33800cc73ee3b4f56143af76a/media/UserAssignedManagedIdentity.png -------------------------------------------------------------------------------- /media/UserAssignedManagedIdentity2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/CosmosDB-Solution-Accelerator-CosmosDB-Helper/9242e5f80141e6f33800cc73ee3b4f56143af76a/media/UserAssignedManagedIdentity2.png -------------------------------------------------------------------------------- /media/Worker Generate Constructor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/CosmosDB-Solution-Accelerator-CosmosDB-Helper/9242e5f80141e6f33800cc73ee3b4f56143af76a/media/Worker Generate Constructor.png -------------------------------------------------------------------------------- /media/add entity class.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/CosmosDB-Solution-Accelerator-CosmosDB-Helper/9242e5f80141e6f33800cc73ee3b4f56143af76a/media/add entity class.png -------------------------------------------------------------------------------- /media/add reference changefeed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/CosmosDB-Solution-Accelerator-CosmosDB-Helper/9242e5f80141e6f33800cc73ee3b4f56143af76a/media/add reference changefeed.png -------------------------------------------------------------------------------- /media/add reference.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/CosmosDB-Solution-Accelerator-CosmosDB-Helper/9242e5f80141e6f33800cc73ee3b4f56143af76a/media/add reference.png -------------------------------------------------------------------------------- /media/add todoservice class.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/CosmosDB-Solution-Accelerator-CosmosDB-Helper/9242e5f80141e6f33800cc73ee3b4f56143af76a/media/add todoservice class.png -------------------------------------------------------------------------------- /media/azure-cosmos-db-create-new-account-detail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/CosmosDB-Solution-Accelerator-CosmosDB-Helper/9242e5f80141e6f33800cc73ee3b4f56143af76a/media/azure-cosmos-db-create-new-account-detail.png -------------------------------------------------------------------------------- /media/dotnet new console.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/CosmosDB-Solution-Accelerator-CosmosDB-Helper/9242e5f80141e6f33800cc73ee3b4f56143af76a/media/dotnet new console.png -------------------------------------------------------------------------------- /media/dotnet new worker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/CosmosDB-Solution-Accelerator-CosmosDB-Helper/9242e5f80141e6f33800cc73ee3b4f56143af76a/media/dotnet new worker.png -------------------------------------------------------------------------------- /media/generate constructor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/CosmosDB-Solution-Accelerator-CosmosDB-Helper/9242e5f80141e6f33800cc73ee3b4f56143af76a/media/generate constructor.png -------------------------------------------------------------------------------- /media/nuget package manager.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/CosmosDB-Solution-Accelerator-CosmosDB-Helper/9242e5f80141e6f33800cc73ee3b4f56143af76a/media/nuget package manager.png -------------------------------------------------------------------------------- /media/override OnChangeFeedDataSets.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/CosmosDB-Solution-Accelerator-CosmosDB-Helper/9242e5f80141e6f33800cc73ee3b4f56143af76a/media/override OnChangeFeedDataSets.png -------------------------------------------------------------------------------- /media/provision cosmosdb mongo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/CosmosDB-Solution-Accelerator-CosmosDB-Helper/9242e5f80141e6f33800cc73ee3b4f56143af76a/media/provision cosmosdb mongo.png -------------------------------------------------------------------------------- /media/switch directory add package.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/CosmosDB-Solution-Accelerator-CosmosDB-Helper/9242e5f80141e6f33800cc73ee3b4f56143af76a/media/switch directory add package.png -------------------------------------------------------------------------------- /media/switch directory add package2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/CosmosDB-Solution-Accelerator-CosmosDB-Helper/9242e5f80141e6f33800cc73ee3b4f56143af76a/media/switch directory add package2.png -------------------------------------------------------------------------------- /media/worker project.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/CosmosDB-Solution-Accelerator-CosmosDB-Helper/9242e5f80141e6f33800cc73ee3b4f56143af76a/media/worker project.png -------------------------------------------------------------------------------- /src/Libraries/Microsoft.Solutions.CosmosDB.Mongo/BusinessTransactionRepository.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using MongoDB.Bson; 5 | using MongoDB.Bson.Serialization; 6 | using MongoDB.Driver; 7 | using MongoDB.Driver.Core; 8 | using System.Collections.Generic; 9 | using System.Threading.Tasks; 10 | using System.Linq; 11 | 12 | 13 | namespace Microsoft.Solutions.CosmosDB.Mongo 14 | { 15 | public class BusinessTransactionRepository : IRepository where TEntity : class, IEntityModel 16 | { 17 | private readonly IMongoDatabase _database; 18 | 19 | public BusinessTransactionRepository(IMongoClient client, string databaseName) 20 | { 21 | _database = client.GetDatabase(databaseName); 22 | 23 | if (!BsonClassMap.IsClassMapRegistered(typeof(TEntity))) 24 | BsonClassMap.RegisterClassMap(); 25 | } 26 | 27 | public async Task GetAsync(TIdentifier id) 28 | { 29 | var result = await _database.GetCollection(typeof(TEntity).Name.ToLowerInvariant()).FindAsync(x => x.id.Equals(id)); 30 | return await result.FirstOrDefaultAsync(); 31 | } 32 | 33 | public async Task FindAsync(ISpecification specification) 34 | { 35 | var collection = _database.GetCollection(typeof(TEntity).Name.ToLowerInvariant()); 36 | return await collection.Find(specification.Predicate).FirstOrDefaultAsync(); 37 | } 38 | 39 | 40 | public async Task> FindAllAsync(FilterDefinition builders) 41 | { 42 | var collection = _database.GetCollection(typeof(TEntity).Name.ToLowerInvariant()); 43 | 44 | return (await collection.FindAsync(builders)).ToList(); 45 | } 46 | 47 | 48 | public async Task> FindAllAsync(ISpecification specification) 49 | { 50 | var collection = _database.GetCollection(typeof(TEntity).Name.ToLowerInvariant()); 51 | 52 | GenericSpecification genericSpecification = specification as GenericSpecification; 53 | 54 | if (genericSpecification.OrderBy == null) 55 | { 56 | return (await collection.FindAsync(specification.Predicate)).ToList(); 57 | } 58 | else if (genericSpecification.Order == Order.Asc) 59 | { 60 | return (await collection.FindAsync(specification.Predicate, new FindOptions() { Sort = Builders.Sort.Ascending(specification.OrderBy) })).ToList(); 61 | 62 | } 63 | else if (genericSpecification.Order == Order.Desc) 64 | { 65 | return (await collection.FindAsync(specification.Predicate, new FindOptions() { Sort = Builders.Sort.Descending(specification.OrderBy) })).ToList(); 66 | } 67 | else 68 | { 69 | return null; 70 | } 71 | } 72 | 73 | 74 | public async Task> GetAllAsync() 75 | { 76 | return (await _database.GetCollection(typeof(TEntity).Name.ToLowerInvariant()).FindAsync(new BsonDocument())).ToList(); 77 | 78 | } 79 | 80 | public async Task> GetAllAsync(IEnumerable identifiers) 81 | { 82 | 83 | List results = new List(); 84 | IMongoCollection collection = _database.GetCollection(typeof(TEntity).Name.ToLowerInvariant()); 85 | foreach (var i in identifiers) 86 | { 87 | results.Add(await this.GetAsync(i)); 88 | } 89 | return results; 90 | } 91 | 92 | public async Task SaveAsync(TEntity entity) 93 | { 94 | var collection = _database.GetCollection(typeof(TEntity).Name.ToLowerInvariant()); 95 | 96 | await collection.ReplaceOneAsync(x => x.id.Equals(entity.id), entity, new ReplaceOptions 97 | { 98 | IsUpsert = true 99 | }); 100 | 101 | return entity; 102 | } 103 | 104 | public async Task AddAsync(TEntity entity) 105 | { 106 | var collection = _database.GetCollection(typeof(TEntity).Name.ToLowerInvariant()); 107 | 108 | await collection.ReplaceOneAsync(x => x.id.Equals(entity.id), entity, new ReplaceOptions 109 | { 110 | IsUpsert = true 111 | }); 112 | 113 | return entity; 114 | } 115 | 116 | public async Task DeleteAsync(TIdentifier entityId, dynamic partitionKeyValue = null) 117 | { 118 | var collection = _database.GetCollection(typeof(TEntity).Name.ToLowerInvariant()); 119 | 120 | await collection.DeleteOneAsync(x => x.id.Equals(entityId)); 121 | } 122 | 123 | public async Task DeleteAsync(TEntity entity, dynamic partitionKeyValue = null) 124 | { 125 | var collection = _database.GetCollection(typeof(TEntity).Name.ToLowerInvariant()); 126 | 127 | await collection.DeleteOneAsync(x => x.id.Equals(entity.id)); 128 | } 129 | 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /src/Libraries/Microsoft.Solutions.CosmosDB.Mongo/Microsoft.Solutions.CosmosDB.Mongo.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net5.0 5 | Microsoft CosmosDB Solution Accelerator - CosmosDB Helper for Mongo API 6 | EAE.Solutions.CosmosDB.Mongo 7 | 0.7.3 8 | Microsoft Solutions 9 | Microsoft Corporation 10 | This library helps using CosmosDB to developers... 11 | true 12 | https://github.com/microsoft/CosmosDB-Solution-Accelerator-CosmosDB-Helper 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/Libraries/Microsoft.Solutions.CosmosDB.Mongo/MongoEntntyCollectionBase.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using MongoDB.Driver; 5 | using System; 6 | 7 | namespace Microsoft.Solutions.CosmosDB.Mongo 8 | { 9 | public class MongoEntntyCollectionBase : IDataRepositoryProvider 10 | where TEntity : class, IEntityModel 11 | { 12 | public IRepository EntityCollection { get; init; } 13 | 14 | public MongoEntntyCollectionBase(string DataConnectionString, string CollectionName) 15 | { 16 | CosmosMongoClientManager.DataconnectionString = DataConnectionString; 17 | MongoClient _client = CosmosMongoClientManager.Instance; 18 | 19 | this.EntityCollection = 20 | new BusinessTransactionRepository(_client, 21 | CollectionName); 22 | 23 | } 24 | } 25 | 26 | public sealed class CosmosMongoClientManager 27 | { 28 | private CosmosMongoClientManager() { } 29 | 30 | static CosmosMongoClientManager() 31 | { 32 | } 33 | 34 | public static string DataconnectionString; 35 | 36 | private static readonly Lazy _instance = 37 | new Lazy(() => new MongoClient(CosmosMongoClientManager.DataconnectionString)); 38 | 39 | public static MongoClient Instance 40 | { 41 | get { return _instance.Value; } 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/Libraries/Microsoft.Solutions.CosmosDB.SQL.ChangeFeed/ChangeFeedProcessorHelper.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using Microsoft.Azure.Cosmos; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Linq; 8 | using System.Text; 9 | using System.Threading.Tasks; 10 | 11 | namespace Microsoft.Solutions.CosmosDB.SQL.ChangeFeed 12 | { 13 | public class ChangeFeedProcessHelper 14 | { 15 | public async Task InitChangeFeedProcessorAsync( 16 | string DataConnectionString, 17 | string SourceDatabaseName, 18 | string MonitoredContainerName, 19 | Container.ChangesHandler ChangeHandler 20 | ) 21 | { 22 | Container leaseContainer; 23 | Database database; 24 | string leaseContainerName = $"{MonitoredContainerName}_lease"; 25 | var processorName = $"{MonitoredContainerName}_changefeedwatcher"; 26 | var instanceName = $"{processorName}_host_{Guid.NewGuid().ToString().Substring(0,8)}"; 27 | 28 | //Initialize CosmosDB Connection 29 | CosmosClient cosmosClient = new CosmosClient(DataConnectionString); 30 | 31 | database = cosmosClient.GetDatabase(SourceDatabaseName); 32 | if (database is null) throw new NullReferenceException("Specified Database doesn't exist"); 33 | 34 | leaseContainer = await database.CreateContainerIfNotExistsAsync(leaseContainerName, "/partitionKey"); 35 | 36 | ChangeFeedProcessor changeFeedProcessor = database.GetContainer(MonitoredContainerName) 37 | .GetChangeFeedProcessorBuilder(processorName: processorName, ChangeHandler) 38 | .WithInstanceName(instanceName) 39 | .WithLeaseContainer(leaseContainer) 40 | .Build(); 41 | 42 | Console.WriteLine($"Starting Change Feed Processor...{processorName} in {instanceName}"); 43 | await changeFeedProcessor.StartAsync(); 44 | Console.WriteLine($"Change Feed Processor {processorName} started in {instanceName}"); 45 | return changeFeedProcessor; 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/Libraries/Microsoft.Solutions.CosmosDB.SQL.ChangeFeed/Microsoft.Solutions.CosmosDB.SQL.ChangeFeed.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net5.0 5 | Microsoft CosmosDB Solution Accelerator - CosmosDB Helper for SQL(using SDK) 6 | EAE.Solutions.CosmosDB.SQL.ChangeFeed 7 | 0.7.3 8 | Microsoft Solutions 9 | Microsoft Corporation 10 | This library helps using CosmosDB to developers... 11 | true 12 | https://github.com/microsoft/CosmosDB-Solution-Accelerator-CosmosDB-Helper 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /src/Libraries/Microsoft.Solutions.CosmosDB.SQL.ChangeFeed/Watcher.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using Microsoft.Azure.Cosmos; 5 | using Microsoft.Extensions.Configuration; 6 | using Microsoft.Extensions.Hosting; 7 | using System; 8 | using System.Collections.Generic; 9 | using System.Linq; 10 | using System.Text; 11 | using System.Threading; 12 | using System.Threading.Tasks; 13 | using Microsoft.Solutions.CosmosDB.SQL; 14 | 15 | namespace Microsoft.Solutions.CosmosDB.SQL.ChangeFeed 16 | { 17 | public class Watcher : BackgroundService 18 | { 19 | readonly string dataConnectionString; 20 | readonly string sourceDatabaseName; 21 | readonly string sourceContainerName; 22 | 23 | private ChangeFeedProcessor changeFeedProcessor; 24 | 25 | public Watcher(string ConnectionString, string MonitoredDatabaseName, string MonitoredContainerName) 26 | { 27 | dataConnectionString = ConnectionString; 28 | sourceDatabaseName = MonitoredDatabaseName; 29 | sourceContainerName = MonitoredContainerName; 30 | 31 | } 32 | 33 | public override async Task StartAsync(CancellationToken cancellationToken) 34 | { 35 | ChangeFeedProcessHelper changeFeedWatcher = new ChangeFeedProcessHelper(); 36 | changeFeedProcessor = await changeFeedWatcher.InitChangeFeedProcessorAsync(dataConnectionString, sourceDatabaseName, sourceContainerName, HandleChangesAsync); 37 | Console.WriteLine("Change feed watcher started"); 38 | } 39 | 40 | public override async Task StopAsync(CancellationToken cancellationToken) 41 | { 42 | await changeFeedProcessor.StopAsync(); 43 | Console.WriteLine("Change feed watcher stopped"); 44 | } 45 | 46 | protected async Task HandleChangesAsync(IReadOnlyCollection changes, CancellationToken cancellationToken) 47 | { 48 | await OnChangedFeedDataSets(changes, cancellationToken); 49 | 50 | } 51 | 52 | protected virtual Task OnChangedFeedDataSets(IReadOnlyCollection changes, CancellationToken cancellationToken) { 53 | return null; 54 | } 55 | 56 | 57 | protected override async Task ExecuteAsync(CancellationToken stoppingToken) 58 | { 59 | while (!stoppingToken.IsCancellationRequested) 60 | { 61 | await Task.Delay(500, stoppingToken); 62 | } 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/Libraries/Microsoft.Solutions.CosmosDB.SQL/BusinessTransactionRepository.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using Microsoft.Azure.Cosmos; 5 | using Microsoft.Azure.Cosmos.Linq; 6 | using System; 7 | using System.Collections.Generic; 8 | using System.Linq; 9 | using System.Threading.Tasks; 10 | using Microsoft.Solutions.CosmosDB; 11 | 12 | namespace Microsoft.Solutions.CosmosDB.SQL 13 | { 14 | 15 | public class BusinessTransactionRepository : IRepository where TEntity : class, IEntityModel 16 | { 17 | private readonly Database _database; 18 | private readonly Container _container; 19 | static bool _checkedDatabase = false; 20 | static bool _checkedContainer = false; 21 | 22 | public BusinessTransactionRepository(CosmosClient client, string DatabaseName, string containerName = "") 23 | { 24 | if (!BusinessTransactionRepository._checkedDatabase) 25 | { 26 | _database = client.CreateDatabaseIfNotExistsAsync(DatabaseName).Result; 27 | BusinessTransactionRepository._checkedDatabase = true; 28 | } 29 | else 30 | { 31 | _database = client.GetDatabase(DatabaseName); 32 | } 33 | 34 | 35 | 36 | if (string.IsNullOrEmpty(containerName)) 37 | { 38 | if (BusinessTransactionRepository._checkedContainer) 39 | { 40 | _container = _database.GetContainer(typeof(TEntity).Name + "s"); 41 | } 42 | else 43 | { 44 | _container = _database.CreateContainerIfNotExistsAsync(typeof(TEntity).Name + "s", "/__partitionkey").Result; 45 | BusinessTransactionRepository._checkedContainer = true; 46 | } 47 | } 48 | else 49 | { 50 | if (BusinessTransactionRepository._checkedContainer) 51 | { 52 | _container = _database.GetContainer(containerName); 53 | } 54 | else 55 | { 56 | try 57 | { 58 | //Try to check it is in the database 59 | _container = _database.CreateContainerAsync(containerName, "/__partitionkey").Result; 60 | BusinessTransactionRepository._checkedContainer = true; 61 | } 62 | catch (Exception ex) 63 | { 64 | var cosmosException = ex.InnerException as CosmosException; 65 | 66 | if ((cosmosException) != null) 67 | if (cosmosException.StatusCode == System.Net.HttpStatusCode.Conflict) 68 | { 69 | _container = _database.GetContainer(containerName); 70 | BusinessTransactionRepository._checkedContainer = true; 71 | } 72 | } 73 | } 74 | } 75 | } 76 | 77 | 78 | public async Task GetAsync(TIdentifier id) 79 | { 80 | var iterator = this._container.GetItemQueryIterator($"select * from c where c.id = '{id.ToString()}'"); 81 | 82 | while (iterator.HasMoreResults) 83 | { 84 | foreach (var item in await iterator.ReadNextAsync()) 85 | { 86 | return item; 87 | } 88 | } 89 | 90 | return null; 91 | } 92 | 93 | public async Task AddAsync(TEntity entity) 94 | { 95 | var result = await this._container.CreateItemAsync(entity); 96 | return result.Resource; 97 | } 98 | 99 | public async Task FindAsync(ISpecification specification) 100 | { 101 | var iterator = this._container.GetItemLinqQueryable().Where(specification.Predicate).ToFeedIterator(); 102 | 103 | while (iterator.HasMoreResults) 104 | { 105 | foreach (var item in await iterator.ReadNextAsync()) 106 | { 107 | return item; 108 | } 109 | } 110 | 111 | return null; 112 | } 113 | 114 | public async Task> GetAllAsync() 115 | { 116 | var iterator = this._container.GetItemLinqQueryable().ToFeedIterator(); 117 | 118 | List results = new List(); 119 | 120 | while (iterator.HasMoreResults) 121 | { 122 | var response = await iterator.ReadNextAsync(); 123 | foreach (var item in response) 124 | { 125 | results.Add(item); 126 | } 127 | } 128 | 129 | return results; 130 | } 131 | 132 | public async Task> FindAllAsync(ISpecification specification) 133 | { 134 | GenericSpecification genericSpecification = specification as GenericSpecification; 135 | 136 | FeedIterator iterator = null; 137 | 138 | if (genericSpecification.OrderBy == null) 139 | { 140 | iterator = this._container.GetItemLinqQueryable().Where(specification.Predicate).ToFeedIterator(); 141 | } 142 | else 143 | { 144 | if (genericSpecification.Order == Order.Asc) 145 | { 146 | iterator = this._container.GetItemLinqQueryable().Where(specification.Predicate).OrderBy(specification.OrderBy).ToFeedIterator(); 147 | } 148 | else 149 | { 150 | iterator = this._container.GetItemLinqQueryable().Where(specification.Predicate).OrderByDescending(specification.OrderBy).ToFeedIterator(); 151 | } 152 | } 153 | 154 | List results = new List(); 155 | 156 | while (iterator.HasMoreResults) 157 | { 158 | var response = await iterator.ReadNextAsync(); 159 | foreach (var item in response) 160 | { 161 | results.Add(item); 162 | } 163 | } 164 | 165 | return results; 166 | } 167 | 168 | public async Task> GetAllAsync(IEnumerable identifiers) 169 | { 170 | List results = new List(); 171 | 172 | foreach (var id in identifiers) 173 | { 174 | var iterator = this._container.GetItemQueryIterator($"select * from c where c.id = '{id.ToString()}'"); 175 | 176 | while (iterator.HasMoreResults) 177 | { 178 | var response = await iterator.ReadNextAsync(); 179 | foreach (var item in response) 180 | { 181 | results.Add(item); 182 | } 183 | } 184 | } 185 | 186 | return results; 187 | 188 | } 189 | 190 | public async Task SaveAsync(TEntity entity) 191 | { 192 | var result = await this._container.ReplaceItemAsync(entity, entity.id.ToString()); 193 | return result.Resource; 194 | 195 | } 196 | 197 | public async Task DeleteAsync(TIdentifier EntityId, dynamic partitionKeyValue = null) 198 | { 199 | var cosmosEntity = await this.GetAsync(EntityId) as TEntity; 200 | 201 | if (partitionKeyValue == null) 202 | { 203 | await this._container.DeleteItemAsync(cosmosEntity.id.ToString(), new PartitionKey(cosmosEntity.__partitionkey)); 204 | } 205 | else 206 | { 207 | await this._container.DeleteItemAsync(cosmosEntity.id.ToString(), new PartitionKey(partitionKeyValue)); 208 | } 209 | } 210 | 211 | public async Task DeleteAsync(TEntity entity, dynamic partitionKeyValue = null) 212 | { 213 | var cosmosEntity = entity as CosmosDBEntityBase; 214 | 215 | if (partitionKeyValue == null) 216 | { 217 | await this._container.DeleteItemAsync(entity.id.ToString(), new PartitionKey(cosmosEntity.__partitionkey)); 218 | } 219 | else 220 | { 221 | await this._container.DeleteItemAsync(entity.id.ToString(), new PartitionKey(partitionKeyValue)); 222 | } 223 | 224 | } 225 | 226 | public async Task Find(ISpecification specification) 227 | { 228 | var iterator = this._container.GetItemLinqQueryable().Where(specification.Predicate).ToFeedIterator(); 229 | 230 | while (iterator.HasMoreResults) 231 | { 232 | foreach (var item in await iterator.ReadNextAsync()) 233 | { 234 | return item; 235 | } 236 | } 237 | 238 | return null; 239 | } 240 | } 241 | } 242 | -------------------------------------------------------------------------------- /src/Libraries/Microsoft.Solutions.CosmosDB.SQL/Microsoft.Solutions.CosmosDB.SQL.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net5.0 5 | Microsoft CosmosDB Solution Accelerator - CosmosDB Helper for SQL(using SDK) 6 | EAE.Solutions.CosmosDB.SQL 7 | 0.7.3 8 | Microsoft Solutions 9 | Microsoft Corporation 10 | This library helps using CosmosDB to developers... 11 | true 12 | https://github.com/microsoft/CosmosDB-Solution-Accelerator-CosmosDB-Helper 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/Libraries/Microsoft.Solutions.CosmosDB.SQL/SQLEntityCollectionBase.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using Microsoft.Azure.Cosmos; 5 | using System; 6 | using System.Diagnostics; 7 | 8 | namespace Microsoft.Solutions.CosmosDB.SQL 9 | { 10 | public class SQLEntityCollectionBase : IDataRepositoryProvider 11 | where TEntity : class, IEntityModel 12 | { 13 | public IRepository EntityCollection { get ; init ; } 14 | 15 | /// 16 | /// 17 | /// 18 | /// Connection String 19 | /// Your Database Name 20 | /// (Optional) If you don't pass it, The Container will be created by Entity Model Class Name + "s", In Model First Dev, You don't need to use it 21 | public SQLEntityCollectionBase(string DataConnectionString, string CollectionName, string ContainerName = "") 22 | { 23 | CosmosClientManager.DataconnectionString = DataConnectionString; 24 | CosmosClient _client = CosmosClientManager.Instance; 25 | 26 | this.EntityCollection = 27 | new BusinessTransactionRepository(_client, 28 | CollectionName, ContainerName); 29 | 30 | } 31 | } 32 | 33 | public sealed class CosmosClientManager 34 | { 35 | private CosmosClientManager() { } 36 | 37 | 38 | static CosmosClientManager() 39 | { 40 | //Type defaultTrace = Type.GetType("Microsoft.Azure.Cosmos.Core.Trace.DefaultTrace,Microsoft.Azure.Cosmos.Direct"); 41 | //TraceSource traceSource = (TraceSource)defaultTrace.GetProperty("TraceSource").GetValue(null); 42 | //traceSource.Switch.Level = SourceLevels.Off; 43 | //traceSource.Listeners.Clear(); 44 | } 45 | 46 | public static string DataconnectionString; 47 | 48 | private static readonly Lazy _instance = 49 | new Lazy(() => new CosmosClient(CosmosClientManager.DataconnectionString)); 50 | 51 | public static CosmosClient Instance 52 | { 53 | get { return _instance.Value; } 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/Libraries/Microsoft.Solutions.CosmosDB.Test/CosmosDBTest.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using Microsoft.VisualStudio.TestTools.UnitTesting; 5 | using System.Threading.Tasks; 6 | using System.Linq; 7 | using System; 8 | using Microsoft.Solutions.CosmosDB.Mongo; 9 | using Microsoft.Solutions.CosmosDB.SQL; 10 | using System.Collections.Generic; 11 | 12 | namespace Microsoft.Solutions.CosmosDB.Test 13 | { 14 | [TestClass] 15 | public class CosmosDBLibTest 16 | { 17 | public static IRepository repository = null; 18 | 19 | private static string cosmossqlConn = "{PUT YOUR COSMOS SQL Core API CONNECTION STRING}"; 20 | private static string cosmosmongoConn = "{PUT YOUR COSMOS MONGO API CONNECTION STRING}"; 21 | 22 | private static dynamic Repository; 23 | 24 | [TestInitialize] 25 | public void TestInit() 26 | { 27 | //Mongo Test 28 | //Repository = new MongoRepository(cosmosmongoConn, "MongoTEST"); 29 | 30 | 31 | 32 | //SQL SDK Test 33 | Repository = new CosmosSQLRepository(cosmossqlConn, "SDKTEST"); 34 | 35 | } 36 | 37 | [TestMethod] 38 | public async Task TEST01_AddAsync() 39 | { 40 | await repository.AddAsync(new Person() { name = "person1", age = 20, gender = Person.Gender.Female, title = "employee" }); 41 | await repository.AddAsync(new Person() { name = "person2", age = 20, gender = Person.Gender.Female, title = "employee" }); 42 | await repository.AddAsync(new Person() { name = "person3", age = 20, gender = Person.Gender.Female, title = "employee" }); 43 | await repository.AddAsync(new Person() { name = "person4", age = 20, gender = Person.Gender.Female, title = "employee" }); 44 | } 45 | 46 | [TestMethod] 47 | public async Task TEST02_SaveAsync() 48 | { 49 | var person1 = await repository.FindAsync(new GenericSpecification(x => x.name == "person1")); 50 | person1.age = 30; 51 | 52 | var person2 = await repository.FindAsync(new GenericSpecification(x => x.name == "person2")); 53 | person2.age = 32; 54 | 55 | var result_person1 = await repository.SaveAsync(person1); 56 | var result_person2 = await repository.SaveAsync(person2); 57 | 58 | Assert.AreEqual(result_person1.age, 30); 59 | Assert.AreEqual(result_person2.age, 32); 60 | 61 | } 62 | 63 | [TestMethod] 64 | public async Task TEST03_Find() 65 | { 66 | var people = await repository.FindAllAsync(new GenericSpecification(x => x.name.StartsWith("person"))); 67 | Assert.IsTrue(people.Count() > 0); 68 | } 69 | 70 | [TestMethod] 71 | public async Task TEST04_Get() 72 | { 73 | var person = await repository.FindAsync(new GenericSpecification(x => x.name == "person1")); 74 | var retperson = await repository.GetAsync(person.id); 75 | 76 | Assert.AreEqual(person.name, retperson.name); 77 | } 78 | 79 | [TestMethod] 80 | public async Task TEST05_FindAllAsync() 81 | { 82 | var results = await repository.FindAllAsync(new GenericSpecification(x => x.age > 10)); 83 | 84 | Console.WriteLine($"{results.Count()} records has been found"); 85 | foreach (var item in results) 86 | { 87 | System.Console.WriteLine($"{item.name} - {item.gender} - {item.title} - {item.age}"); 88 | } 89 | 90 | Console.WriteLine($"Order by name ASC"); 91 | results = await repository.FindAllAsync(new GenericSpecification(x => x.age > 10, x => x.name, Order.Asc)); 92 | foreach (var item in results) 93 | { 94 | System.Console.WriteLine($"{item.name} - {item.gender} - {item.title} - {item.age}"); 95 | } 96 | 97 | Console.WriteLine($"Order by name DESC"); 98 | results = await repository.FindAllAsync(new GenericSpecification(x => x.age > 10, x => x.name, Order.Desc)); 99 | foreach (var item in results) 100 | { 101 | System.Console.WriteLine($"{item.name} - {item.gender} - {item.title} - {item.age}"); 102 | } 103 | 104 | 105 | Assert.AreNotSame(0, results.Count()); 106 | } 107 | 108 | [TestMethod] 109 | public async Task TEST06_GetAllAsync() 110 | { 111 | var results = await repository.GetAllAsync(); 112 | Console.WriteLine($"{results.Count()} records has been recorded"); 113 | 114 | Assert.AreNotEqual(results.Count(), 0); 115 | } 116 | 117 | [TestMethod] 118 | public async Task TEST07_FindAllAsync() 119 | { 120 | var _over30agedpeople = await repository.FindAllAsync(new GenericSpecification(x => x.age > 30)); 121 | var results = await repository.GetAllAsync(_over30agedpeople.Select(x => x.id).ToArray()); 122 | 123 | Console.WriteLine($"{results.Count()} objsts has been recorded"); 124 | Assert.AreEqual(results.Count(), _over30agedpeople.Count()); 125 | } 126 | 127 | [TestMethod] 128 | public async Task TEST08_DeleteAsync() 129 | { 130 | var _30agedperson = await repository.FindAsync(new GenericSpecification(x => x.age == 30)); 131 | _30agedperson.title = "employeer"; 132 | 133 | await repository.DeleteAsync(_30agedperson); 134 | 135 | Console.WriteLine($"{_30agedperson.id} object has been deleted"); 136 | } 137 | 138 | [TestMethod] 139 | public async Task TEST09_DeleteAsync() 140 | { 141 | var _30agedperson = await repository.FindAsync(new GenericSpecification(x => x.age == 32)); 142 | _30agedperson.title = "employeer"; 143 | 144 | await repository.DeleteAsync(_30agedperson.id); 145 | 146 | Console.WriteLine($"{_30agedperson.id} object has been deleted"); 147 | } 148 | } 149 | 150 | public class MongoRepository : MongoEntntyCollectionBase 151 | { 152 | public MongoRepository(string DataConnectionString, string CollectionName) : base(DataConnectionString, CollectionName) 153 | { 154 | CosmosDBLibTest.repository = this.EntityCollection; 155 | } 156 | } 157 | 158 | public class CosmosSQLRepository : SQLEntityCollectionBase 159 | { 160 | public CosmosSQLRepository(string DataConnectionString, string CollectionName) : base(DataConnectionString, CollectionName) 161 | { 162 | CosmosDBLibTest.repository = this.EntityCollection; 163 | } 164 | } 165 | 166 | public class Person : CosmosDBEntityBase 167 | { 168 | public string name { get; set; } 169 | public int age { get; set; } 170 | public string title { get; set; } 171 | public Gender gender { get; set; } 172 | public enum Gender { Male, Female, NoN } 173 | } 174 | } 175 | -------------------------------------------------------------------------------- /src/Libraries/Microsoft.Solutions.CosmosDB.Test/Microsoft.Solutions.CosmosDB.Test.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net5.0 5 | 6 | false 7 | 8 | 9 | 10 | 1701;1702;CS0414 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | all 19 | runtime; build; native; contentfiles; analyzers; buildtransitive 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /src/Libraries/Microsoft.Solutions.CosmosDB/CosmosDBEntityBase.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System; 5 | using System.Security.Cryptography; 6 | using System.Text; 7 | 8 | namespace Microsoft.Solutions.CosmosDB 9 | { 10 | public class CosmosDBEntityBase : IEntityModel 11 | { 12 | public CosmosDBEntityBase() 13 | { 14 | this.id = Guid.NewGuid().ToString(); 15 | this.__partitionkey = CosmosDBEntityBase.GetKey(id, 9999); 16 | } 17 | 18 | /// 19 | /// id will be generated automatically. you don't need to manage it by yourself 20 | /// 21 | public string id { get; set; } 22 | 23 | /// 24 | /// the partitionkey will be used for storage partitioning. you don't need to manage it by yourself 25 | /// 26 | public string __partitionkey { get; set; } 27 | 28 | static SHA1 _sha1; 29 | 30 | static CosmosDBEntityBase() 31 | { 32 | _sha1 = SHA1.Create(); 33 | } 34 | 35 | /// 36 | /// Generate partitionkey for CosmosDB 37 | /// using SHA1 hash with id, convert it to uint and divide with number of partitions 38 | /// assigned default value as 9999 (9999 partition at this moment) 39 | /// 40 | /// 41 | /// 42 | /// 43 | public static string GetKey(string id, int numberofPartitions) 44 | { 45 | var hasedVal = _sha1.ComputeHash(Encoding.UTF8.GetBytes(id)); 46 | var intHashedVal = BitConverter.ToUInt32(hasedVal, 0); 47 | 48 | var range = numberofPartitions - 1; 49 | var length = range.ToString().Length; 50 | 51 | var key = (intHashedVal % numberofPartitions).ToString(); 52 | return key.PadLeft(length, '0'); 53 | } 54 | 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/Libraries/Microsoft.Solutions.CosmosDB/GenericSpecification.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System; 5 | using System.Linq.Expressions; 6 | 7 | namespace Microsoft.Solutions.CosmosDB 8 | { 9 | public class GenericSpecification : ISpecification 10 | { 11 | public GenericSpecification(Expression> predicate, Expression> orderBy = null, Order order = Order.Asc) 12 | { 13 | Predicate = predicate; 14 | OrderBy = orderBy; 15 | Order = order; 16 | } 17 | /// 18 | /// Gets or sets the func delegate query to execute against the repository for searching records. 19 | /// 20 | public Expression> Predicate { get; } 21 | public Expression> OrderBy { get; } 22 | public Order Order { get; } 23 | } 24 | 25 | public enum Order 26 | { 27 | Asc, 28 | Desc 29 | } 30 | } -------------------------------------------------------------------------------- /src/Libraries/Microsoft.Solutions.CosmosDB/IDataRepositoryProvider.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | namespace Microsoft.Solutions.CosmosDB 5 | { 6 | /// 7 | /// Interface for DI in each CosmosDB Helpers 8 | /// 9 | /// 10 | public interface IDataRepositoryProvider 11 | { 12 | /// 13 | /// Entity Object Collections which has Database CRUD operations 14 | /// 15 | IRepository EntityCollection { get; init ; } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Libraries/Microsoft.Solutions.CosmosDB/IEntityModel.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | namespace Microsoft.Solutions.CosmosDB 5 | { 6 | /// 7 | /// Every Entnties have to follow this interface 8 | /// Unique identifier type should be string 9 | /// 10 | /// 11 | public interface IEntityModel 12 | { 13 | TIdentifier id { get; set; } 14 | string __partitionkey { get; set; } 15 | } 16 | } -------------------------------------------------------------------------------- /src/Libraries/Microsoft.Solutions.CosmosDB/IRepository.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System.Collections.Generic; 5 | using System.Threading.Tasks; 6 | 7 | namespace Microsoft.Solutions.CosmosDB 8 | { 9 | /// 10 | /// Default CRUD operations in CosmosDB 11 | /// 12 | /// 13 | /// 14 | public interface IRepository 15 | { 16 | Task AddAsync(TEntity entity); 17 | Task DeleteAsync(TEntity entit, dynamic partitionKeyValue = null); 18 | Task DeleteAsync(TIdentifier entityId, dynamic partitionKeyValue = null); 19 | Task FindAsync(ISpecification specification); 20 | Task> FindAllAsync(ISpecification specification); 21 | Task GetAsync(TIdentifier id); 22 | Task> GetAllAsync(); 23 | Task> GetAllAsync(IEnumerable identifiers); 24 | Task SaveAsync(TEntity entity); 25 | } 26 | } -------------------------------------------------------------------------------- /src/Libraries/Microsoft.Solutions.CosmosDB/ISpecification.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System; 5 | using System.Linq.Expressions; 6 | 7 | namespace Microsoft.Solutions.CosmosDB 8 | { 9 | public interface ISpecification 10 | { 11 | /// 12 | /// Gets or sets the func delegate query to execute against the repository for searching records. 13 | /// 14 | Expression> Predicate { get; } 15 | Expression> OrderBy { get; } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Libraries/Microsoft.Solutions.CosmosDB/Microsoft.Solutions.CosmosDB.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net5.0 5 | https://github.com/microsoft/CosmosDB-Solution-Accelerator-CosmosDB-Helper 6 | EAE.Solutions.CosmosDB 7 | 0.7.3 8 | Microsoft Solutions 9 | Microsoft Corporation 10 | True 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/Microsoft CosmosDB Solution Accelerator.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.1.31911.260 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Samples", "Samples", "{E36FC976-3345-4988-B710-C7F5DEAD2EF6}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Solutions.CosmosDB.Mongo.TODO.Service", "Sample\Microsoft.Solutions.CosmosDB.Mongo.TODO.Service\Microsoft.Solutions.CosmosDB.Mongo.TODO.Service.csproj", "{9AD83669-5DE8-44E5-9C12-BAD90FB93A23}" 9 | EndProject 10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Solutions.CosmosDB.Mongo.TODO.Tests", "Sample\Microsoft.Solutions.CosmosDB.Mongo.TODO.Tests\Microsoft.Solutions.CosmosDB.Mongo.TODO.Tests.csproj", "{E36ADD7C-3E12-44D5-9A56-0B5C086EF755}" 11 | EndProject 12 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Mongo", "Mongo", "{1FE0C1A9-B34A-4B9A-8B13-9342D28B849E}" 13 | EndProject 14 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Libraries", "Libraries", "{F75FAB67-13B6-4A4D-8FD9-C30D4A7B648F}" 15 | EndProject 16 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Solutions.CosmosDB.SQL", "libraries\Microsoft.Solutions.CosmosDB.SQL\Microsoft.Solutions.CosmosDB.SQL.csproj", "{A161FC5B-E3D9-4814-BFFB-90FD8AE1E158}" 17 | EndProject 18 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SQL", "SQL", "{9CF5C149-650A-42C4-A08E-0A066FE7721A}" 19 | EndProject 20 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Solutions.CosmosDB.SQL.TODO.Service", "Sample\Microsoft.Solutions.CosmosDB.SQL.SDK.TODO.Service\Microsoft.Solutions.CosmosDB.SQL.TODO.Service.csproj", "{79FBDE75-2C12-4684-ADCB-C8004D305373}" 21 | EndProject 22 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Solutions.CosmosDB.SQL.TODO.Service.Tests", "Sample\Microsoft.Solutions.CosmosDB.SQL.SDK.TODO.Service.Tests\Microsoft.Solutions.CosmosDB.SQL.TODO.Service.Tests.csproj", "{7C6EAD80-D219-4792-98D7-247248918968}" 23 | EndProject 24 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Solutions.CosmosDB", "libraries\Microsoft.Solutions.CosmosDB\Microsoft.Solutions.CosmosDB.csproj", "{5CF6B6AA-635A-46A3-A0BC-A84294BB205E}" 25 | EndProject 26 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Solutions.CosmosDB.TODO.WebHost", "Sample\Microsoft.Solutions.CosmosDB.WebHost\Microsoft.Solutions.CosmosDB.TODO.WebHost.csproj", "{8926C6B9-213D-4569-A878-53204473E75E}" 27 | EndProject 28 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Solutions.CosmosDB.SQL.ChangeFeed", "Libraries\Microsoft.Solutions.CosmosDB.SQL.ChangeFeed\Microsoft.Solutions.CosmosDB.SQL.ChangeFeed.csproj", "{45D30D7D-271F-4833-8E80-09831F79F1E5}" 29 | EndProject 30 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Solutions.CosmosDB.SQL.ChangeFeed.Service", "Sample\Microsoft.Solutions.CosmosDB.SQL.ChangeFeed.Service\Microsoft.Solutions.CosmosDB.SQL.ChangeFeed.Service.csproj", "{0F6953CF-37F3-4759-AF46-A62ABB49D76C}" 31 | EndProject 32 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Solutions.CosmosDB.Test", "libraries\Microsoft.Solutions.CosmosDB.Test\Microsoft.Solutions.CosmosDB.Test.csproj", "{228A0A82-EF20-459D-A9CD-564EC02A45E2}" 33 | EndProject 34 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Solutions.CosmosDB.Security.ManagedIdentity", "libraries\Microsoft.Solutions.CosmosDB.Security.ManagedIdentity\Microsoft.Solutions.CosmosDB.Security.ManagedIdentity.csproj", "{88B10D30-4A93-4BC0-9CF5-F813B40A6943}" 35 | EndProject 36 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Utils", "Utils", "{1E21D3A9-D00F-45AF-99EC-BF8123ACE33F}" 37 | EndProject 38 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Solutions.HTTP", "Utils\Microsoft.Solutions.HTTP\Microsoft.Solutions.HTTP.csproj", "{50FC98FF-EAE1-478D-B9F9-846DA11372AD}" 39 | EndProject 40 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Solutions.CosmosDB.Mongo", "libraries\Microsoft.Solutions.CosmosDB.Mongo\Microsoft.Solutions.CosmosDB.Mongo.csproj", "{43EAD90D-01D0-4468-BD44-86D20A88F947}" 41 | EndProject 42 | Global 43 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 44 | Debug|Any CPU = Debug|Any CPU 45 | DebugWithSymbol|Any CPU = DebugWithSymbol|Any CPU 46 | Release|Any CPU = Release|Any CPU 47 | EndGlobalSection 48 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 49 | {9AD83669-5DE8-44E5-9C12-BAD90FB93A23}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 50 | {9AD83669-5DE8-44E5-9C12-BAD90FB93A23}.Debug|Any CPU.Build.0 = Debug|Any CPU 51 | {9AD83669-5DE8-44E5-9C12-BAD90FB93A23}.DebugWithSymbol|Any CPU.ActiveCfg = Debug|Any CPU 52 | {9AD83669-5DE8-44E5-9C12-BAD90FB93A23}.DebugWithSymbol|Any CPU.Build.0 = Debug|Any CPU 53 | {9AD83669-5DE8-44E5-9C12-BAD90FB93A23}.Release|Any CPU.ActiveCfg = Release|Any CPU 54 | {9AD83669-5DE8-44E5-9C12-BAD90FB93A23}.Release|Any CPU.Build.0 = Release|Any CPU 55 | {E36ADD7C-3E12-44D5-9A56-0B5C086EF755}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 56 | {E36ADD7C-3E12-44D5-9A56-0B5C086EF755}.Debug|Any CPU.Build.0 = Debug|Any CPU 57 | {E36ADD7C-3E12-44D5-9A56-0B5C086EF755}.DebugWithSymbol|Any CPU.ActiveCfg = Debug|Any CPU 58 | {E36ADD7C-3E12-44D5-9A56-0B5C086EF755}.DebugWithSymbol|Any CPU.Build.0 = Debug|Any CPU 59 | {E36ADD7C-3E12-44D5-9A56-0B5C086EF755}.Release|Any CPU.ActiveCfg = Release|Any CPU 60 | {E36ADD7C-3E12-44D5-9A56-0B5C086EF755}.Release|Any CPU.Build.0 = Release|Any CPU 61 | {A161FC5B-E3D9-4814-BFFB-90FD8AE1E158}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 62 | {A161FC5B-E3D9-4814-BFFB-90FD8AE1E158}.Debug|Any CPU.Build.0 = Debug|Any CPU 63 | {A161FC5B-E3D9-4814-BFFB-90FD8AE1E158}.DebugWithSymbol|Any CPU.ActiveCfg = Debug|Any CPU 64 | {A161FC5B-E3D9-4814-BFFB-90FD8AE1E158}.DebugWithSymbol|Any CPU.Build.0 = Debug|Any CPU 65 | {A161FC5B-E3D9-4814-BFFB-90FD8AE1E158}.Release|Any CPU.ActiveCfg = Release|Any CPU 66 | {A161FC5B-E3D9-4814-BFFB-90FD8AE1E158}.Release|Any CPU.Build.0 = Release|Any CPU 67 | {79FBDE75-2C12-4684-ADCB-C8004D305373}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 68 | {79FBDE75-2C12-4684-ADCB-C8004D305373}.Debug|Any CPU.Build.0 = Debug|Any CPU 69 | {79FBDE75-2C12-4684-ADCB-C8004D305373}.DebugWithSymbol|Any CPU.ActiveCfg = Debug|Any CPU 70 | {79FBDE75-2C12-4684-ADCB-C8004D305373}.DebugWithSymbol|Any CPU.Build.0 = Debug|Any CPU 71 | {79FBDE75-2C12-4684-ADCB-C8004D305373}.Release|Any CPU.ActiveCfg = Release|Any CPU 72 | {79FBDE75-2C12-4684-ADCB-C8004D305373}.Release|Any CPU.Build.0 = Release|Any CPU 73 | {7C6EAD80-D219-4792-98D7-247248918968}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 74 | {7C6EAD80-D219-4792-98D7-247248918968}.Debug|Any CPU.Build.0 = Debug|Any CPU 75 | {7C6EAD80-D219-4792-98D7-247248918968}.DebugWithSymbol|Any CPU.ActiveCfg = Debug|Any CPU 76 | {7C6EAD80-D219-4792-98D7-247248918968}.DebugWithSymbol|Any CPU.Build.0 = Debug|Any CPU 77 | {7C6EAD80-D219-4792-98D7-247248918968}.Release|Any CPU.ActiveCfg = Release|Any CPU 78 | {7C6EAD80-D219-4792-98D7-247248918968}.Release|Any CPU.Build.0 = Release|Any CPU 79 | {5CF6B6AA-635A-46A3-A0BC-A84294BB205E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 80 | {5CF6B6AA-635A-46A3-A0BC-A84294BB205E}.Debug|Any CPU.Build.0 = Debug|Any CPU 81 | {5CF6B6AA-635A-46A3-A0BC-A84294BB205E}.DebugWithSymbol|Any CPU.ActiveCfg = Debug|Any CPU 82 | {5CF6B6AA-635A-46A3-A0BC-A84294BB205E}.DebugWithSymbol|Any CPU.Build.0 = Debug|Any CPU 83 | {5CF6B6AA-635A-46A3-A0BC-A84294BB205E}.Release|Any CPU.ActiveCfg = Release|Any CPU 84 | {5CF6B6AA-635A-46A3-A0BC-A84294BB205E}.Release|Any CPU.Build.0 = Release|Any CPU 85 | {8926C6B9-213D-4569-A878-53204473E75E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 86 | {8926C6B9-213D-4569-A878-53204473E75E}.Debug|Any CPU.Build.0 = Debug|Any CPU 87 | {8926C6B9-213D-4569-A878-53204473E75E}.DebugWithSymbol|Any CPU.ActiveCfg = Debug|Any CPU 88 | {8926C6B9-213D-4569-A878-53204473E75E}.DebugWithSymbol|Any CPU.Build.0 = Debug|Any CPU 89 | {8926C6B9-213D-4569-A878-53204473E75E}.Release|Any CPU.ActiveCfg = Release|Any CPU 90 | {8926C6B9-213D-4569-A878-53204473E75E}.Release|Any CPU.Build.0 = Release|Any CPU 91 | {45D30D7D-271F-4833-8E80-09831F79F1E5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 92 | {45D30D7D-271F-4833-8E80-09831F79F1E5}.Debug|Any CPU.Build.0 = Debug|Any CPU 93 | {45D30D7D-271F-4833-8E80-09831F79F1E5}.DebugWithSymbol|Any CPU.ActiveCfg = Debug|Any CPU 94 | {45D30D7D-271F-4833-8E80-09831F79F1E5}.DebugWithSymbol|Any CPU.Build.0 = Debug|Any CPU 95 | {45D30D7D-271F-4833-8E80-09831F79F1E5}.Release|Any CPU.ActiveCfg = Release|Any CPU 96 | {45D30D7D-271F-4833-8E80-09831F79F1E5}.Release|Any CPU.Build.0 = Release|Any CPU 97 | {0F6953CF-37F3-4759-AF46-A62ABB49D76C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 98 | {0F6953CF-37F3-4759-AF46-A62ABB49D76C}.Debug|Any CPU.Build.0 = Debug|Any CPU 99 | {0F6953CF-37F3-4759-AF46-A62ABB49D76C}.DebugWithSymbol|Any CPU.ActiveCfg = Debug|Any CPU 100 | {0F6953CF-37F3-4759-AF46-A62ABB49D76C}.DebugWithSymbol|Any CPU.Build.0 = Debug|Any CPU 101 | {0F6953CF-37F3-4759-AF46-A62ABB49D76C}.Release|Any CPU.ActiveCfg = Release|Any CPU 102 | {0F6953CF-37F3-4759-AF46-A62ABB49D76C}.Release|Any CPU.Build.0 = Release|Any CPU 103 | {228A0A82-EF20-459D-A9CD-564EC02A45E2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 104 | {228A0A82-EF20-459D-A9CD-564EC02A45E2}.Debug|Any CPU.Build.0 = Debug|Any CPU 105 | {228A0A82-EF20-459D-A9CD-564EC02A45E2}.DebugWithSymbol|Any CPU.ActiveCfg = Debug|Any CPU 106 | {228A0A82-EF20-459D-A9CD-564EC02A45E2}.DebugWithSymbol|Any CPU.Build.0 = Debug|Any CPU 107 | {228A0A82-EF20-459D-A9CD-564EC02A45E2}.Release|Any CPU.ActiveCfg = Release|Any CPU 108 | {228A0A82-EF20-459D-A9CD-564EC02A45E2}.Release|Any CPU.Build.0 = Release|Any CPU 109 | {88B10D30-4A93-4BC0-9CF5-F813B40A6943}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 110 | {88B10D30-4A93-4BC0-9CF5-F813B40A6943}.Debug|Any CPU.Build.0 = Debug|Any CPU 111 | {88B10D30-4A93-4BC0-9CF5-F813B40A6943}.DebugWithSymbol|Any CPU.ActiveCfg = Debug|Any CPU 112 | {88B10D30-4A93-4BC0-9CF5-F813B40A6943}.DebugWithSymbol|Any CPU.Build.0 = Debug|Any CPU 113 | {88B10D30-4A93-4BC0-9CF5-F813B40A6943}.Release|Any CPU.ActiveCfg = Release|Any CPU 114 | {88B10D30-4A93-4BC0-9CF5-F813B40A6943}.Release|Any CPU.Build.0 = Release|Any CPU 115 | {50FC98FF-EAE1-478D-B9F9-846DA11372AD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 116 | {50FC98FF-EAE1-478D-B9F9-846DA11372AD}.Debug|Any CPU.Build.0 = Debug|Any CPU 117 | {50FC98FF-EAE1-478D-B9F9-846DA11372AD}.DebugWithSymbol|Any CPU.ActiveCfg = Debug|Any CPU 118 | {50FC98FF-EAE1-478D-B9F9-846DA11372AD}.DebugWithSymbol|Any CPU.Build.0 = Debug|Any CPU 119 | {50FC98FF-EAE1-478D-B9F9-846DA11372AD}.Release|Any CPU.ActiveCfg = Release|Any CPU 120 | {50FC98FF-EAE1-478D-B9F9-846DA11372AD}.Release|Any CPU.Build.0 = Release|Any CPU 121 | {43EAD90D-01D0-4468-BD44-86D20A88F947}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 122 | {43EAD90D-01D0-4468-BD44-86D20A88F947}.Debug|Any CPU.Build.0 = Debug|Any CPU 123 | {43EAD90D-01D0-4468-BD44-86D20A88F947}.DebugWithSymbol|Any CPU.ActiveCfg = Debug|Any CPU 124 | {43EAD90D-01D0-4468-BD44-86D20A88F947}.DebugWithSymbol|Any CPU.Build.0 = Debug|Any CPU 125 | {43EAD90D-01D0-4468-BD44-86D20A88F947}.Release|Any CPU.ActiveCfg = Release|Any CPU 126 | {43EAD90D-01D0-4468-BD44-86D20A88F947}.Release|Any CPU.Build.0 = Release|Any CPU 127 | EndGlobalSection 128 | GlobalSection(SolutionProperties) = preSolution 129 | HideSolutionNode = FALSE 130 | EndGlobalSection 131 | GlobalSection(NestedProjects) = preSolution 132 | {9AD83669-5DE8-44E5-9C12-BAD90FB93A23} = {1FE0C1A9-B34A-4B9A-8B13-9342D28B849E} 133 | {E36ADD7C-3E12-44D5-9A56-0B5C086EF755} = {1FE0C1A9-B34A-4B9A-8B13-9342D28B849E} 134 | {1FE0C1A9-B34A-4B9A-8B13-9342D28B849E} = {E36FC976-3345-4988-B710-C7F5DEAD2EF6} 135 | {A161FC5B-E3D9-4814-BFFB-90FD8AE1E158} = {F75FAB67-13B6-4A4D-8FD9-C30D4A7B648F} 136 | {9CF5C149-650A-42C4-A08E-0A066FE7721A} = {E36FC976-3345-4988-B710-C7F5DEAD2EF6} 137 | {79FBDE75-2C12-4684-ADCB-C8004D305373} = {9CF5C149-650A-42C4-A08E-0A066FE7721A} 138 | {7C6EAD80-D219-4792-98D7-247248918968} = {9CF5C149-650A-42C4-A08E-0A066FE7721A} 139 | {5CF6B6AA-635A-46A3-A0BC-A84294BB205E} = {F75FAB67-13B6-4A4D-8FD9-C30D4A7B648F} 140 | {8926C6B9-213D-4569-A878-53204473E75E} = {E36FC976-3345-4988-B710-C7F5DEAD2EF6} 141 | {45D30D7D-271F-4833-8E80-09831F79F1E5} = {F75FAB67-13B6-4A4D-8FD9-C30D4A7B648F} 142 | {0F6953CF-37F3-4759-AF46-A62ABB49D76C} = {9CF5C149-650A-42C4-A08E-0A066FE7721A} 143 | {228A0A82-EF20-459D-A9CD-564EC02A45E2} = {F75FAB67-13B6-4A4D-8FD9-C30D4A7B648F} 144 | {88B10D30-4A93-4BC0-9CF5-F813B40A6943} = {F75FAB67-13B6-4A4D-8FD9-C30D4A7B648F} 145 | {50FC98FF-EAE1-478D-B9F9-846DA11372AD} = {1E21D3A9-D00F-45AF-99EC-BF8123ACE33F} 146 | {43EAD90D-01D0-4468-BD44-86D20A88F947} = {F75FAB67-13B6-4A4D-8FD9-C30D4A7B648F} 147 | EndGlobalSection 148 | GlobalSection(ExtensibilityGlobals) = postSolution 149 | SolutionGuid = {5A9383CD-0E2F-46A6-8783-0315851AAD4C} 150 | EndGlobalSection 151 | EndGlobal 152 | -------------------------------------------------------------------------------- /src/Sample/Microsoft.Solutions.CosmosDB.Mongo.TODO.Service/Microsoft.Solutions.CosmosDB.Mongo.TODO.Service.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net5.0 5 | Debug;Release 6 | 7 | 8 | 9 | TRACE;MONGO 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/Sample/Microsoft.Solutions.CosmosDB.Mongo.TODO.Service/Models/TODO.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System; 5 | 6 | namespace Microsoft.Solutions.CosmosDB.Mongo.TODO.Service.Models 7 | { 8 | public class ToDo : CosmosDBEntityBase 9 | { 10 | public string title { get; set; } 11 | public Status status { get; set; } 12 | public DateTime startDate { get; set; } 13 | public DateTime endDate { get; set; } 14 | public string notes { get; set; } 15 | 16 | private int _percentComplete; 17 | 18 | public int percentComplete 19 | { 20 | get { return _percentComplete; } 21 | set 22 | { 23 | if ((percentComplete < 0) || (percentComplete > 100)) 24 | { 25 | throw new OverflowException("percent value should be between 0 to 100"); 26 | } 27 | else 28 | { 29 | _percentComplete = percentComplete; 30 | } 31 | } 32 | } 33 | } 34 | 35 | public enum Status { New, InProcess, Done } 36 | } 37 | -------------------------------------------------------------------------------- /src/Sample/Microsoft.Solutions.CosmosDB.Mongo.TODO.Service/TODOService.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Threading.Tasks; 7 | using Microsoft.Solutions.CosmosDB.Mongo.TODO.Service.Models; 8 | 9 | namespace Microsoft.Solutions.CosmosDB.Mongo.TODO.Service 10 | { 11 | public class TODOService : MongoEntntyCollectionBase 12 | { 13 | public TODOService(string DataConnectionString, string CollectionName) : base(DataConnectionString, CollectionName) 14 | { 15 | 16 | } 17 | 18 | public async Task Create(string title, Status status, int percentComplete, DateTime startDate, DateTime endDate, string notes) 19 | { 20 | return await this.EntityCollection.AddAsync( 21 | new ToDo() 22 | { 23 | title = title, 24 | status = status, 25 | percentComplete = percentComplete, 26 | startDate = startDate, 27 | endDate = endDate, 28 | notes = notes 29 | } 30 | ); 31 | } 32 | 33 | public async Task Update(ToDo todo) 34 | { 35 | return await this.EntityCollection.SaveAsync(todo); 36 | } 37 | 38 | public async Task Delete(string id) 39 | { 40 | await this.EntityCollection.DeleteAsync(id); 41 | } 42 | 43 | public async Task Find(string id) 44 | { 45 | return await this.EntityCollection.GetAsync(id); 46 | } 47 | 48 | public async Task> Search(string notes) 49 | { 50 | return await this.EntityCollection.FindAllAsync(new GenericSpecification(x => x.notes.Contains(notes))); 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/Sample/Microsoft.Solutions.CosmosDB.Mongo.TODO.Tests/Microsoft.Solutions.CosmosDB.Mongo.TODO.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net5.0 5 | 6 | false 7 | 8 | 9 | 10 | TRACE;MONGO 11 | false 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/Sample/Microsoft.Solutions.CosmosDB.Mongo.TODO.Tests/TODOServiceTests.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using Microsoft.Solutions.CosmosDB.Mongo.TODO.Service; 5 | using Microsoft.Solutions.CosmosDB.Mongo.TODO.Service.Models; 6 | using Microsoft.VisualStudio.TestTools.UnitTesting; 7 | using Newtonsoft.Json; 8 | using System; 9 | using System.Threading.Tasks; 10 | 11 | namespace Microsoft.Solutions.CosmosDB.Mongo.TODO.Tests 12 | { 13 | [TestClass()] 14 | public class TODOServiceTests 15 | { 16 | static TODOService todoService; 17 | static string mongoConnString = "{Put Your ConnectionString}"; 18 | static string objectId; 19 | 20 | [TestInitialize] 21 | public void InitTest() 22 | { 23 | todoService = new TODOService(mongoConnString, "COSMOSDB-MONGO"); 24 | } 25 | 26 | 27 | [TestMethod()] 28 | public async Task TEST01_CreateTODOTest() 29 | { 30 | var result = await todoService.Create("test title", Status.New, 0, DateTime.Today, DateTime.Today.AddDays(7), "bla bla"); 31 | objectId = result.id; 32 | } 33 | 34 | [TestMethod()] 35 | public async Task TEST02_UpdateTODOTest() 36 | { 37 | var createdTodoObj = await todoService.Find(objectId); 38 | createdTodoObj.notes = "updated bla bla"; 39 | 40 | await todoService.Update(createdTodoObj); 41 | 42 | } 43 | 44 | [TestMethod()] 45 | public async Task TEST03_SearchTODOTest() 46 | { 47 | var todos = await todoService.Search("updated"); 48 | 49 | foreach (var todo in todos) 50 | { 51 | Console.WriteLine($"{todo.id} - {todo.status} - {todo.notes}"); 52 | } 53 | } 54 | 55 | [TestMethod()] 56 | public async Task TEST04_RemoveTODOTest() 57 | { 58 | var createdTodoObj = await todoService.Find(objectId); 59 | Console.WriteLine($"{JsonConvert.SerializeObject(createdTodoObj)} will be removed"); 60 | await todoService.Delete(objectId); 61 | } 62 | 63 | } 64 | } -------------------------------------------------------------------------------- /src/Sample/Microsoft.Solutions.CosmosDB.SQL.ChangeFeed.Service/Dockerfile: -------------------------------------------------------------------------------- 1 | #See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging. 2 | 3 | FROM mcr.microsoft.com/dotnet/runtime:5.0 AS base 4 | WORKDIR /app 5 | 6 | FROM mcr.microsoft.com/dotnet/sdk:5.0 AS build 7 | WORKDIR /src 8 | COPY ["Sample/Microsoft.Solutions.CosmosDB.SQL.ChangeFeed.Service/Microsoft.Solutions.CosmosDB.SQL.ChangeFeed.Service.csproj", "Sample/Microsoft.Solutions.CosmosDB.SQL.ChangeFeed.Service/"] 9 | COPY ["libraries/Microsoft.Solutions.CosmosDB.SQL.ChangeFeed/Microsoft.Solutions.CosmosDB.SQL.ChangeFeed.csproj", "libraries/Microsoft.Solutions.CosmosDB.SQL.ChangeFeed/"] 10 | COPY ["libraries/Microsoft.Solutions.CosmosDB/Microsoft.Solutions.CosmosDB.csproj", "libraries/Microsoft.Solutions.CosmosDB/"] 11 | COPY ["libraries/Microsoft.Solutions.CosmosDB.SQL/Microsoft.Solutions.CosmosDB.SQL.csproj", "libraries/Microsoft.Solutions.CosmosDB.SQL/"] 12 | RUN dotnet restore "Sample/Microsoft.Solutions.CosmosDB.SQL.ChangeFeed.Service/Microsoft.Solutions.CosmosDB.SQL.ChangeFeed.Service.csproj" 13 | COPY . . 14 | WORKDIR "/src/Sample/Microsoft.Solutions.CosmosDB.SQL.ChangeFeed.Service" 15 | RUN dotnet build "Microsoft.Solutions.CosmosDB.SQL.ChangeFeed.Service.csproj" -c Release -o /app/build 16 | 17 | FROM build AS publish 18 | RUN dotnet publish "Microsoft.Solutions.CosmosDB.SQL.ChangeFeed.Service.csproj" -c Release -o /app/publish 19 | 20 | FROM base AS final 21 | WORKDIR /app 22 | COPY --from=publish /app/publish . 23 | ENTRYPOINT ["dotnet", "Microsoft.Solutions.CosmosDB.SQL.TODO.ChangeFeed.Service.dll"] -------------------------------------------------------------------------------- /src/Sample/Microsoft.Solutions.CosmosDB.SQL.ChangeFeed.Service/Microsoft.Solutions.CosmosDB.SQL.ChangeFeed.Service.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net5.0 5 | dotnet-Microsoft.Solutions.CosmosDB.SQL.ChangeFeed.Service-C3808731-9407-4BE4-85FA-FA48ADFBF125 6 | Linux 7 | ..\.. 8 | Microsoft.Solutions.CosmosDB.SQL.TODO.ChangeFeed.Service 9 | Microsoft.Solutions.CosmosDB.SQL.TODO.ChangeFeed.Service 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/Sample/Microsoft.Solutions.CosmosDB.SQL.ChangeFeed.Service/Models/TODO.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System; 5 | 6 | namespace Microsoft.Solutions.CosmosDB.SQL.ChangeFeed.Service.Models 7 | { 8 | public class ToDo : CosmosDBEntityBase 9 | { 10 | public string title { get; set; } 11 | public Status status { get; set; } 12 | public DateTime startDate { get; set; } 13 | public DateTime endDate { get; set; } 14 | public string notes { get; set; } 15 | 16 | private int _percentComplete; 17 | 18 | public int percentComplete 19 | { 20 | get { return _percentComplete; } 21 | set 22 | { 23 | if ((percentComplete < 0) || (percentComplete > 100)) 24 | { 25 | throw new OverflowException("percent value should be between 0 to 100"); 26 | } 27 | else 28 | { 29 | _percentComplete = percentComplete; 30 | } 31 | } 32 | } 33 | } 34 | 35 | public enum Status { New, InProcess, Done } 36 | } 37 | -------------------------------------------------------------------------------- /src/Sample/Microsoft.Solutions.CosmosDB.SQL.ChangeFeed.Service/Program.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.DependencyInjection; 2 | using Microsoft.Extensions.Hosting; 3 | using Microsoft.Solutions.CosmosDB.SQL.ChangeFeed.Service.Models; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using System.Threading.Tasks; 8 | 9 | namespace Microsoft.Solutions.CosmosDB.SQL.TODO.ChangeFeed.Service 10 | { 11 | public class Program 12 | { 13 | public static void Main(string[] args) 14 | { 15 | CreateHostBuilder(args).Build().Run(); 16 | } 17 | 18 | public static IHostBuilder CreateHostBuilder(string[] args) => 19 | Host.CreateDefaultBuilder(args) 20 | .ConfigureServices((hostContext, services) => 21 | { 22 | services.AddHostedService(); 23 | }); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Sample/Microsoft.Solutions.CosmosDB.SQL.ChangeFeed.Service/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "Microsoft.Solutions.CosmosDB.SQL.ChangeFeed.Service": { 4 | "commandName": "Project", 5 | "environmentVariables": { 6 | "DOTNET_ENVIRONMENT": "Development" 7 | }, 8 | "dotnetRunMessages": "true" 9 | }, 10 | "Docker": { 11 | "commandName": "Docker" 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /src/Sample/Microsoft.Solutions.CosmosDB.SQL.ChangeFeed.Service/Worker.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Configuration; 2 | using Microsoft.Solutions.CosmosDB.SQL.ChangeFeed; 3 | using Microsoft.Solutions.CosmosDB.SQL.ChangeFeed.Service.Models; 4 | using Newtonsoft.Json; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Threading; 8 | using System.Threading.Tasks; 9 | 10 | namespace Microsoft.Solutions.CosmosDB.SQL.TODO.ChangeFeed.Service 11 | { 12 | public class Worker : Watcher 13 | { 14 | /// 15 | /// Passing configuration by ASPnet core Dependency Injection 16 | /// This Application sample shows how to detact changes for TODO collection by Microsoft.Solutions.CosmosDB.SQL.TODO.WebHost Demo App 17 | /// 18 | /// Check appsettings.json file definition 19 | public Worker(IConfiguration configuration) : base(configuration["Values:DBConnectionString"], 20 | configuration["Values:MonitoredDatabaseName"], 21 | configuration["Values:MonitoredContainerName"]) 22 | { 23 | } 24 | 25 | protected override Task OnChangedFeedDataSets(IReadOnlyCollection changes, CancellationToken cancellationToken) 26 | { 27 | //put your business logics with changes 28 | foreach (var item in changes) 29 | { 30 | Console.WriteLine($"Detected operation for item with id {item.id} => {JsonConvert.SerializeObject(item)}"); 31 | } 32 | 33 | return base.OnChangedFeedDataSets(changes, cancellationToken); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Sample/Microsoft.Solutions.CosmosDB.SQL.ChangeFeed.Service/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft": "Warning", 6 | "Microsoft.Hosting.Lifetime": "Information" 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/Sample/Microsoft.Solutions.CosmosDB.SQL.ChangeFeed.Service/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft": "Warning", 6 | "Microsoft.Hosting.Lifetime": "Information" 7 | } 8 | }, 9 | "Values": { 10 | "DBConnectionString": "{Put Your ConnectionString}", 11 | "MonitoredDatabaseName": "COSMOS-SQLSDK", 12 | "MonitoredContainerName": "ToDos" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/Sample/Microsoft.Solutions.CosmosDB.SQL.SDK.TODO.Service.Tests/Microsoft.Solutions.CosmosDB.SQL.TODO.Service.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net5.0 5 | 6 | false 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/Sample/Microsoft.Solutions.CosmosDB.SQL.SDK.TODO.Service.Tests/TODOServiceTests.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using Microsoft.VisualStudio.TestTools.UnitTesting; 5 | using System; 6 | using System.Threading.Tasks; 7 | using Microsoft.Solutions.CosmosDB.SQL.SDK.TODO.Service.Models; 8 | 9 | namespace Microsoft.Solutions.CosmosDB.SQL.SDK.TODO.Service.Tests 10 | { 11 | [TestClass()] 12 | public class TODOServiceTests 13 | { 14 | static TODOService todoService; 15 | static string connString = "{PUT YOUR COSMOS SQL Core API CONNECTION STRING}"; 16 | static string objectId; 17 | 18 | [TestInitialize] 19 | public void InitTest() 20 | { 21 | todoService = new TODOService(connString, "COSMOS-SQLSDK", "CosmosToDo"); 22 | } 23 | 24 | 25 | [TestMethod()] 26 | public async Task TEST01_CreateTODOTest() 27 | { 28 | var result = await todoService.Create("test title", Status.New, 0, DateTime.Today, DateTime.Today.AddDays(7), "bla bla"); 29 | objectId = result.id; 30 | Console.WriteLine(objectId); 31 | } 32 | 33 | [TestMethod()] 34 | public async Task TEST02_UpdateTODOTest() 35 | { 36 | var createdTodoObj = await todoService.Find(objectId); 37 | createdTodoObj.notes = "updated bla bla"; 38 | 39 | await todoService.Update(createdTodoObj); 40 | 41 | } 42 | 43 | [TestMethod()] 44 | public async Task TEST03_SearchTODOTest() 45 | { 46 | var todos = await todoService.Search("updated"); 47 | 48 | foreach (var todo in todos) 49 | { 50 | Console.WriteLine($"{todo.id} - {todo.status} - {todo.notes}"); 51 | } 52 | } 53 | 54 | [TestMethod()] 55 | public async Task TEST04_RemoveTODOTest() 56 | { 57 | var createdTodoObj = await todoService.Find(objectId); 58 | Console.WriteLine($"{createdTodoObj} will be removed"); 59 | await todoService.Delete(objectId); 60 | } 61 | } 62 | } -------------------------------------------------------------------------------- /src/Sample/Microsoft.Solutions.CosmosDB.SQL.SDK.TODO.Service/Microsoft.Solutions.CosmosDB.SQL.TODO.Service.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net5.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/Sample/Microsoft.Solutions.CosmosDB.SQL.SDK.TODO.Service/Models/TODO.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System; 5 | 6 | namespace Microsoft.Solutions.CosmosDB.SQL.SDK.TODO.Service.Models 7 | { 8 | public class ToDo : CosmosDBEntityBase 9 | { 10 | public string title { get; set; } 11 | public Status status { get; set; } 12 | public DateTime startDate { get; set; } 13 | public DateTime endDate { get; set; } 14 | public string notes { get; set; } 15 | 16 | private int _percentComplete; 17 | 18 | public int percentComplete 19 | { 20 | get { return _percentComplete; } 21 | set 22 | { 23 | if ((percentComplete < 0) || (percentComplete > 100)) 24 | { 25 | throw new OverflowException("percent value should be between 0 to 100"); 26 | } 27 | else 28 | { 29 | _percentComplete = percentComplete; 30 | } 31 | } 32 | } 33 | } 34 | 35 | public enum Status { New, InProcess, Done } 36 | } 37 | -------------------------------------------------------------------------------- /src/Sample/Microsoft.Solutions.CosmosDB.SQL.SDK.TODO.Service/TODOService.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using Microsoft.Solutions.CosmosDB.SQL.SDK.TODO.Service.Models; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Threading.Tasks; 8 | 9 | namespace Microsoft.Solutions.CosmosDB.SQL.SDK.TODO.Service 10 | { 11 | public class TODOService : SQLEntityCollectionBase 12 | { 13 | public TODOService(string DataConnectionString, string CollectionName, string EntitySetName) : base(DataConnectionString, CollectionName, EntitySetName) 14 | { 15 | } 16 | 17 | public async Task Create(string title, Status status, int percentComplete, DateTime startDate, DateTime endDate, string notes) 18 | { 19 | return await this.EntityCollection.AddAsync( 20 | new ToDo() 21 | { 22 | title = title, 23 | status = status, 24 | percentComplete = percentComplete, 25 | startDate = startDate, 26 | endDate = endDate, 27 | notes = notes 28 | } 29 | ); 30 | } 31 | 32 | public async Task Update(ToDo todo) 33 | { 34 | return await this.EntityCollection.SaveAsync(todo); 35 | } 36 | 37 | public async Task Delete(string id) 38 | { 39 | await this.EntityCollection.DeleteAsync(id); 40 | } 41 | 42 | public async Task Find(string id) 43 | { 44 | return await this.EntityCollection.GetAsync(id); 45 | } 46 | 47 | public async Task> Search(string notes) 48 | { 49 | return await this.EntityCollection.FindAllAsync(new GenericSpecification(x => x.notes.Contains(notes))); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/Sample/Microsoft.Solutions.CosmosDB.WebHost/Controllers/ToDoController.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using Microsoft.AspNetCore.Mvc; 5 | using Microsoft.Solutions.CosmosDB.SQL.SDK.TODO.Service.Models; 6 | using System.Collections.Generic; 7 | using System.Threading.Tasks; 8 | 9 | namespace Microsoft.Solutions.CosmosDB.TODO.WebHost.Controllers 10 | { 11 | [ApiController] 12 | [Route("[controller]")] 13 | public class ToDoController : ControllerBase 14 | { 15 | private IDataRepositoryProvider todoRepo; 16 | 17 | public ToDoController(IDataRepositoryProvider repo) 18 | { 19 | todoRepo = repo; 20 | } 21 | 22 | [HttpGet] 23 | public async Task> Get() 24 | { 25 | return await todoRepo.EntityCollection.GetAllAsync(); 26 | } 27 | 28 | [HttpGet] 29 | [Route("FindNotes")] 30 | public async Task> FindNotes(string searchValue) 31 | { 32 | return await todoRepo.EntityCollection.FindAllAsync(new GenericSpecification(x => x.notes.Contains(searchValue))); 33 | } 34 | 35 | [HttpGet] 36 | [Route("FindTitle")] 37 | public async Task> FindTitle(string searchValue) 38 | { 39 | return await todoRepo.EntityCollection.FindAllAsync(new GenericSpecification(x => x.title.Contains(searchValue))); 40 | } 41 | 42 | [HttpPost] 43 | public async Task AddNew(ToDo todo) 44 | { 45 | return await todoRepo.EntityCollection.AddAsync( 46 | new ToDo() 47 | { 48 | title = todo.title, 49 | startDate = todo.startDate, 50 | endDate = todo.endDate, 51 | notes = todo.notes, 52 | percentComplete = todo.percentComplete, 53 | status = todo.status 54 | } 55 | ); 56 | } 57 | 58 | [HttpDelete] 59 | public async Task Delete(string id) 60 | { 61 | await todoRepo.EntityCollection.DeleteAsync(id); 62 | } 63 | 64 | [HttpPut] 65 | public async Task Update(ToDo todo) 66 | { 67 | await todoRepo.EntityCollection.SaveAsync(todo); 68 | } 69 | 70 | 71 | 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/Sample/Microsoft.Solutions.CosmosDB.WebHost/Dockerfile: -------------------------------------------------------------------------------- 1 | #See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging. 2 | 3 | FROM mcr.microsoft.com/dotnet/aspnet:5.0 AS base 4 | WORKDIR /app 5 | EXPOSE 80 6 | EXPOSE 443 7 | 8 | FROM mcr.microsoft.com/dotnet/sdk:5.0 AS build 9 | WORKDIR /src 10 | COPY ["Sample/Microsoft.Solutions.CosmosDB.WebHost/Microsoft.Solutions.CosmosDB.TODO.WebHost.csproj", "Sample/Microsoft.Solutions.CosmosDB.WebHost/"] 11 | COPY ["Sample/Microsoft.Solutions.CosmosDB.SQL.SDK.TODO.Service/Microsoft.Solutions.CosmosDB.SQL.TODO.Service.csproj", "Sample/Microsoft.Solutions.CosmosDB.SQL.SDK.TODO.Service/"] 12 | COPY ["libraries/Microsoft.Solutions.CosmosDB/Microsoft.Solutions.CosmosDB.csproj", "libraries/Microsoft.Solutions.CosmosDB/"] 13 | COPY ["libraries/Microsoft.Solutions.CosmosDB.SQL/Microsoft.Solutions.CosmosDB.SQL.csproj", "libraries/Microsoft.Solutions.CosmosDB.SQL/"] 14 | RUN dotnet restore "Sample/Microsoft.Solutions.CosmosDB.WebHost/Microsoft.Solutions.CosmosDB.TODO.WebHost.csproj" 15 | COPY . . 16 | WORKDIR "/src/Sample/Microsoft.Solutions.CosmosDB.WebHost" 17 | RUN dotnet build "Microsoft.Solutions.CosmosDB.TODO.WebHost.csproj" -c Release -o /app/build 18 | 19 | FROM build AS publish 20 | RUN dotnet publish "Microsoft.Solutions.CosmosDB.TODO.WebHost.csproj" -c Release -o /app/publish 21 | 22 | FROM base AS final 23 | WORKDIR /app 24 | COPY --from=publish /app/publish . 25 | ENTRYPOINT ["dotnet", "Microsoft.Solutions.CosmosDB.TODO.WebHost.dll"] -------------------------------------------------------------------------------- /src/Sample/Microsoft.Solutions.CosmosDB.WebHost/Microsoft.Solutions.CosmosDB.TODO.WebHost.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net5.0 5 | e0d84ef4-7119-4d28-931f-66d3d32289f1 6 | Linux 7 | ..\.. 8 | Microsoft.Solutions.CosmosDB.TODO.WebHost.Program 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/Sample/Microsoft.Solutions.CosmosDB.WebHost/Program.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using Microsoft.AspNetCore.Hosting; 5 | using Microsoft.Extensions.Hosting; 6 | 7 | namespace Microsoft.Solutions.CosmosDB.TODO.WebHost 8 | { 9 | public class Program 10 | { 11 | public static void Main(string[] args) 12 | { 13 | CreateHostBuilder(args).Build().Run(); 14 | } 15 | 16 | public static IHostBuilder CreateHostBuilder(string[] args) => 17 | Host.CreateDefaultBuilder(args) 18 | .ConfigureWebHostDefaults(webBuilder => 19 | { 20 | webBuilder.UseStartup(); 21 | }); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/Sample/Microsoft.Solutions.CosmosDB.WebHost/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true, 5 | "iisExpress": { 6 | "applicationUrl": "http://localhost:55132", 7 | "sslPort": 44380 8 | } 9 | }, 10 | "$schema": "http://json.schemastore.org/launchsettings.json", 11 | "profiles": { 12 | "IIS Express": { 13 | "commandName": "IISExpress", 14 | "launchBrowser": true, 15 | "launchUrl": "swagger", 16 | "environmentVariables": { 17 | "ASPNETCORE_ENVIRONMENT": "Development" 18 | } 19 | }, 20 | "WebApplication1": { 21 | "commandName": "Project", 22 | "launchBrowser": true, 23 | "launchUrl": "swagger", 24 | "environmentVariables": { 25 | "ASPNETCORE_ENVIRONMENT": "Development" 26 | }, 27 | "dotnetRunMessages": "true", 28 | "applicationUrl": "https://localhost:5001;http://localhost:5000" 29 | }, 30 | "Docker": { 31 | "commandName": "Docker", 32 | "launchBrowser": true, 33 | "launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}/swagger", 34 | "publishAllPorts": true, 35 | "useSSL": true 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /src/Sample/Microsoft.Solutions.CosmosDB.WebHost/Startup.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using Microsoft.AspNetCore.Builder; 5 | using Microsoft.AspNetCore.Hosting; 6 | using Microsoft.Extensions.Configuration; 7 | using Microsoft.Extensions.DependencyInjection; 8 | using Microsoft.Extensions.Hosting; 9 | using Microsoft.OpenApi.Models; 10 | using Microsoft.Solutions.CosmosDB.Security.ManagedIdentity; 11 | using Microsoft.Solutions.CosmosDB.SQL.SDK.TODO.Service; 12 | using Microsoft.Solutions.CosmosDB.SQL.SDK.TODO.Service.Models; 13 | using System.Threading.Tasks; 14 | 15 | namespace Microsoft.Solutions.CosmosDB.TODO.WebHost 16 | { 17 | public class Startup 18 | { 19 | public Startup(IConfiguration configuration) 20 | { 21 | Configuration = configuration; 22 | } 23 | 24 | public IConfiguration Configuration { get; } 25 | 26 | // This method gets called by the runtime. Use this method to add services to the container. 27 | public void ConfigureServices(IServiceCollection services) 28 | { 29 | 30 | services.AddControllers(); 31 | services.AddCosmosHelper(Configuration); 32 | services.AddSwaggerGen(c => 33 | { 34 | c.SwaggerDoc("v1", new OpenApiInfo { Title = "Contoso TODO Web API", Version = "v1" }); 35 | }); 36 | } 37 | 38 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. 39 | public void Configure(IApplicationBuilder app, IWebHostEnvironment env) 40 | { 41 | if (env.IsDevelopment()) 42 | { 43 | app.UseDeveloperExceptionPage(); 44 | app.UseSwagger(); 45 | app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "Contoso TODO Web API v1")); 46 | } 47 | 48 | app.UseHttpsRedirection(); 49 | 50 | app.UseRouting(); 51 | 52 | app.UseAuthorization(); 53 | 54 | app.UseEndpoints(endpoints => 55 | { 56 | endpoints.MapControllers(); 57 | }); 58 | } 59 | } 60 | 61 | static class CustomExtensionsMethods 62 | { 63 | public static IServiceCollection AddCosmosHelper(this IServiceCollection services, IConfiguration configuration) 64 | { 65 | services.AddTransient, TODOService>(x => { return new TODOService(ConnectionStringHelper.GetConnectionString(configuration).Result, "CosmosHandson", "ToDoSample"); }); 66 | 67 | return services; 68 | } 69 | } 70 | 71 | static class ConnectionStringHelper 72 | { 73 | private static string _connectionString; 74 | 75 | public async static Task GetConnectionString(IConfiguration Configuration) 76 | { 77 | if (!string.IsNullOrEmpty(ConnectionStringHelper._connectionString)) return ConnectionStringHelper._connectionString; 78 | 79 | var objConnectionStrings = await ConnectionStringAccessor.Create(Configuration["App:SubscriptionId"], 80 | Configuration["App:ResourceGroupName"], 81 | Configuration["App:DatabaseAccountName"]) 82 | .GetConnectionStringsAsync(Configuration["App:ManagedIdentityId"]); 83 | ConnectionStringHelper._connectionString = objConnectionStrings.PrimaryReadWriteKey; 84 | 85 | return ConnectionStringHelper._connectionString; 86 | } 87 | } 88 | 89 | } 90 | -------------------------------------------------------------------------------- /src/Sample/Microsoft.Solutions.CosmosDB.WebHost/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft": "Warning", 6 | "Microsoft.Hosting.Lifetime": "Information" 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/Sample/Microsoft.Solutions.CosmosDB.WebHost/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft": "Warning", 6 | "Microsoft.Hosting.Lifetime": "Information" 7 | } 8 | }, 9 | "AllowedHosts": "*", 10 | "App": { 11 | "SubscriptionId": "{Put Your Subscription Id}", 12 | "ResourceGroupName": "{Put Your Resourcegroup Name}", 13 | "ManagedIdentityId": "{Put Your Managed Identity Client Id}", 14 | "DatabaseAccountName": "{Put Your CosmosDB Account Name}" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/Sample/Microsoft.Solutions.CosmosDB.WebHost/azds.yaml: -------------------------------------------------------------------------------- 1 | kind: helm-release 2 | apiVersion: 1.1 3 | build: 4 | context: ..\.. 5 | dockerfile: Dockerfile 6 | install: 7 | chart: charts/microsoftsolutionscosmosdbwebhost 8 | values: 9 | - values.dev.yaml? 10 | - secrets.dev.yaml? 11 | set: 12 | # Optionally, specify an array of imagePullSecrets. These secrets must be manually created in the namespace. 13 | # This will override the imagePullSecrets array in values.yaml file. 14 | # If the dockerfile specifies any private registry, the imagePullSecret for that registry must be added here. 15 | # ref: https://kubernetes.io/docs/concepts/containers/images/#specifying-imagepullsecrets-on-a-pod 16 | # 17 | # For example, the following uses credentials from secret "myRegistryKeySecretName". 18 | # 19 | # imagePullSecrets: 20 | # - name: myRegistryKeySecretName 21 | replicaCount: 1 22 | image: 23 | repository: microsoftsolutionscosmosdbwebhost 24 | tag: $(tag) 25 | pullPolicy: Never 26 | ingress: 27 | annotations: 28 | kubernetes.io/ingress.class: traefik-azds 29 | hosts: 30 | # This expands to form the service's public URL: [space.s.][rootSpace.]microsoftsolutionscosmosdbwebhost...azds.io 31 | # Customize the public URL by changing the 'microsoftsolutionscosmosdbwebhost' text between the $(rootSpacePrefix) and $(hostSuffix) tokens 32 | # For more information see https://aka.ms/devspaces/routing 33 | - $(spacePrefix)$(rootSpacePrefix)microsoftsolutionscosmosdbwebhost$(hostSuffix) 34 | configurations: 35 | develop: 36 | build: 37 | dockerfile: Dockerfile.develop 38 | useGitIgnore: true 39 | args: 40 | BUILD_CONFIGURATION: ${BUILD_CONFIGURATION:-Debug} 41 | container: 42 | sync: 43 | - "**/Pages/**" 44 | - "**/Views/**" 45 | - "**/wwwroot/**" 46 | - "!**/*.{sln,csproj}" 47 | command: [dotnet, run, --no-restore, --no-build, --no-launch-profile, -c, "${BUILD_CONFIGURATION:-Debug}"] 48 | iterate: 49 | processesToKill: [dotnet, vsdbg, Microsoft,Solutions.CosmosDB.TODO.WebHost] 50 | buildCommands: 51 | - [dotnet, build, --no-restore, -c, "${BUILD_CONFIGURATION:-Debug}"] 52 | -------------------------------------------------------------------------------- /src/Sample/Microsoft.Solutions.CosmosDB.WebHost/charts/microsoftsolutionscosmosdbwebhost/.helmignore: -------------------------------------------------------------------------------- 1 | # Patterns to ignore when building packages. 2 | # This supports shell glob matching, relative path matching, and 3 | # negation (prefixed with !). Only one pattern per line. 4 | .DS_Store 5 | # Common VCS dirs 6 | .git/ 7 | .gitignore 8 | .bzr/ 9 | .bzrignore 10 | .hg/ 11 | .hgignore 12 | .svn/ 13 | # Common backup files 14 | *.swp 15 | *.bak 16 | *.tmp 17 | *~ 18 | # Various IDEs 19 | .project 20 | .idea/ 21 | *.tmproj 22 | -------------------------------------------------------------------------------- /src/Sample/Microsoft.Solutions.CosmosDB.WebHost/charts/microsoftsolutionscosmosdbwebhost/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | appVersion: "1.0" 3 | description: A Helm chart for Kubernetes 4 | name: microsoftsolutionscosmosdbwebhost 5 | version: 0.1.0 6 | -------------------------------------------------------------------------------- /src/Sample/Microsoft.Solutions.CosmosDB.WebHost/charts/microsoftsolutionscosmosdbwebhost/templates/NOTES.txt: -------------------------------------------------------------------------------- 1 | 1. Get the application URL by running these commands: 2 | {{- if .Values.ingress.enabled }} 3 | {{- range .Values.ingress.hosts }} 4 | http{{ if $.Values.ingress.tls }}s{{ end }}://{{ . }}{{ $.Values.ingress.path }} 5 | {{- end }} 6 | {{- else if contains "NodePort" .Values.service.type }} 7 | export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "microsoftsolutionscosmosdbwebhost.fullname" . }}) 8 | export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") 9 | echo http://$NODE_IP:$NODE_PORT 10 | {{- else if contains "LoadBalancer" .Values.service.type }} 11 | NOTE: It may take a few minutes for the LoadBalancer IP to be available. 12 | You can watch the status of by running 'kubectl get svc -w {{ template "microsoftsolutionscosmosdbwebhost.fullname" . }}' 13 | export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "microsoftsolutionscosmosdbwebhost.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}') 14 | echo http://$SERVICE_IP:{{ .Values.service.port }} 15 | {{- else if contains "ClusterIP" .Values.service.type }} 16 | export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app={{ template "microsoftsolutionscosmosdbwebhost.name" . }},release={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") 17 | echo "Visit http://127.0.0.1:8080 to use your application" 18 | kubectl port-forward $POD_NAME 8080:80 19 | {{- end }} 20 | -------------------------------------------------------------------------------- /src/Sample/Microsoft.Solutions.CosmosDB.WebHost/charts/microsoftsolutionscosmosdbwebhost/templates/_helpers.tpl: -------------------------------------------------------------------------------- 1 | {{/* vim: set filetype=mustache: */}} 2 | {{/* 3 | Expand the name of the chart. 4 | */}} 5 | {{- define "microsoftsolutionscosmosdbwebhost.name" -}} 6 | {{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} 7 | {{- end -}} 8 | 9 | {{/* 10 | Create a default fully qualified app name. 11 | We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). 12 | If release name contains chart name it will be used as a full name. 13 | */}} 14 | {{- define "microsoftsolutionscosmosdbwebhost.fullname" -}} 15 | {{- if .Values.fullnameOverride -}} 16 | {{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} 17 | {{- else -}} 18 | {{- $name := default .Chart.Name .Values.nameOverride -}} 19 | {{- if contains $name .Release.Name -}} 20 | {{- .Release.Name | trunc 63 | trimSuffix "-" -}} 21 | {{- else -}} 22 | {{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} 23 | {{- end -}} 24 | {{- end -}} 25 | {{- end -}} 26 | 27 | {{/* 28 | Create chart name and version as used by the chart label. 29 | */}} 30 | {{- define "microsoftsolutionscosmosdbwebhost.chart" -}} 31 | {{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} 32 | {{- end -}} 33 | -------------------------------------------------------------------------------- /src/Sample/Microsoft.Solutions.CosmosDB.WebHost/charts/microsoftsolutionscosmosdbwebhost/templates/deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: {{ template "microsoftsolutionscosmosdbwebhost.fullname" . }} 5 | labels: 6 | app: {{ template "microsoftsolutionscosmosdbwebhost.name" . }} 7 | chart: {{ template "microsoftsolutionscosmosdbwebhost.chart" . }} 8 | draft: {{ .Values.draft | default "draft-app" }} 9 | release: {{ .Release.Name }} 10 | heritage: {{ .Release.Service }} 11 | spec: 12 | revisionHistoryLimit: 0 13 | replicas: {{ .Values.replicaCount }} 14 | selector: 15 | matchLabels: 16 | app: {{ template "microsoftsolutionscosmosdbwebhost.name" . }} 17 | release: {{ .Release.Name }} 18 | template: 19 | metadata: 20 | labels: 21 | app: {{ template "microsoftsolutionscosmosdbwebhost.name" . }} 22 | draft: {{ .Values.draft | default "draft-app" }} 23 | release: {{ .Release.Name }} 24 | annotations: 25 | buildID: {{ .Values.buildID | default "" | quote }} 26 | spec: 27 | containers: 28 | - name: {{ .Chart.Name }} 29 | image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" 30 | imagePullPolicy: {{ .Values.image.pullPolicy }} 31 | ports: 32 | - name: http 33 | containerPort: {{ .Values.deployment.containerPort }} 34 | protocol: TCP 35 | {{- if .Values.probes.enabled }} 36 | livenessProbe: 37 | httpGet: 38 | path: / 39 | port: http 40 | readinessProbe: 41 | httpGet: 42 | path: / 43 | port: http 44 | {{- end }} 45 | env: 46 | {{- $root := . }} 47 | {{- range $ref, $values := .Values.secrets }} 48 | {{- range $key, $value := $values }} 49 | - name: {{ $ref }}_{{ $key }} 50 | valueFrom: 51 | secretKeyRef: 52 | name: {{ template "microsoftsolutionscosmosdbwebhost.fullname" $root }}-{{ $ref | lower }} 53 | key: {{ $key }} 54 | {{- end }} 55 | {{- end }} 56 | resources: 57 | {{ toYaml .Values.resources | indent 12 }} 58 | {{- with .Values.imagePullSecrets }} 59 | imagePullSecrets: 60 | {{ toYaml . | indent 8 }} 61 | {{- end }} 62 | {{- with .Values.nodeSelector }} 63 | nodeSelector: 64 | {{ toYaml . | indent 8 }} 65 | {{- end }} 66 | {{- with .Values.affinity }} 67 | affinity: 68 | {{ toYaml . | indent 8 }} 69 | {{- end }} 70 | {{- with .Values.tolerations }} 71 | tolerations: 72 | {{ toYaml . | indent 8 }} 73 | {{- end }} 74 | -------------------------------------------------------------------------------- /src/Sample/Microsoft.Solutions.CosmosDB.WebHost/charts/microsoftsolutionscosmosdbwebhost/templates/ingress.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.ingress.enabled -}} 2 | {{- $fullName := include "microsoftsolutionscosmosdbwebhost.fullname" . -}} 3 | {{- $servicePort := .Values.service.port -}} 4 | {{- $ingressPath := .Values.ingress.path -}} 5 | {{- if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}} 6 | apiVersion: networking.k8s.io/v1beta1 7 | {{- else -}} 8 | apiVersion: extensions/v1beta1 9 | {{- end }} 10 | kind: Ingress 11 | metadata: 12 | name: {{ $fullName }} 13 | labels: 14 | app: {{ template "microsoftsolutionscosmosdbwebhost.name" . }} 15 | chart: {{ template "microsoftsolutionscosmosdbwebhost.chart" . }} 16 | release: {{ .Release.Name }} 17 | heritage: {{ .Release.Service }} 18 | {{- with .Values.ingress.annotations }} 19 | annotations: 20 | {{ toYaml . | indent 4 }} 21 | {{- end }} 22 | spec: 23 | {{- if .Values.ingress.tls }} 24 | tls: 25 | {{- range .Values.ingress.tls }} 26 | - hosts: 27 | {{- range .hosts }} 28 | - {{ . }} 29 | {{- end }} 30 | secretName: {{ .secretName }} 31 | {{- end }} 32 | {{- end }} 33 | rules: 34 | {{- range .Values.ingress.hosts }} 35 | - host: {{ . }} 36 | http: 37 | paths: 38 | - path: {{ $ingressPath }} 39 | backend: 40 | serviceName: {{ $fullName }} 41 | servicePort: http 42 | {{- end }} 43 | {{- end }} 44 | -------------------------------------------------------------------------------- /src/Sample/Microsoft.Solutions.CosmosDB.WebHost/charts/microsoftsolutionscosmosdbwebhost/templates/secrets.yaml: -------------------------------------------------------------------------------- 1 | {{- $root := . }} 2 | {{- range $name, $values := .Values.secrets }} 3 | apiVersion: v1 4 | kind: Secret 5 | metadata: 6 | name: {{ template "microsoftsolutionscosmosdbwebhost.fullname" $root }}-{{ $name | lower }} 7 | data: 8 | {{- range $key, $value := $values }} 9 | {{ $key }}: {{ $value | b64enc }} 10 | {{- end }} 11 | --- 12 | {{- end }} 13 | -------------------------------------------------------------------------------- /src/Sample/Microsoft.Solutions.CosmosDB.WebHost/charts/microsoftsolutionscosmosdbwebhost/templates/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: {{ template "microsoftsolutionscosmosdbwebhost.fullname" . }} 5 | labels: 6 | app: {{ template "microsoftsolutionscosmosdbwebhost.name" . }} 7 | chart: {{ template "microsoftsolutionscosmosdbwebhost.chart" . }} 8 | release: {{ .Release.Name }} 9 | heritage: {{ .Release.Service }} 10 | spec: 11 | type: {{ .Values.service.type }} 12 | ports: 13 | - port: {{ .Values.service.port }} 14 | targetPort: http 15 | protocol: TCP 16 | name: http 17 | selector: 18 | app: {{ template "microsoftsolutionscosmosdbwebhost.name" . }} 19 | release: {{ .Release.Name }} 20 | -------------------------------------------------------------------------------- /src/Sample/Microsoft.Solutions.CosmosDB.WebHost/charts/microsoftsolutionscosmosdbwebhost/values.yaml: -------------------------------------------------------------------------------- 1 | # Default values for microsoftsolutionscosmosdbwebhost. 2 | # This is a YAML-formatted file. 3 | # Declare variables to be passed into your templates. 4 | fullnameOverride: microsoftsolutionscosmosdbwebhost 5 | replicaCount: 1 6 | image: 7 | repository: microsoftsolutionscosmosdbwebhost 8 | tag: stable 9 | pullPolicy: IfNotPresent 10 | imagePullSecrets: [] 11 | # Optionally specify an array of imagePullSecrets. 12 | # Secrets must be manually created in the namespace. 13 | # ref: https://kubernetes.io/docs/concepts/containers/images/#specifying-imagepullsecrets-on-a-pod 14 | # 15 | # This uses credentials from secret "myRegistryKeySecretName". 16 | # - name: myRegistryKeySecretName 17 | service: 18 | type: ClusterIP 19 | port: 80 20 | 21 | deployment: 22 | containerPort: 80 23 | 24 | probes: 25 | enabled: false 26 | 27 | ingress: 28 | enabled: false 29 | annotations: {} 30 | # kubernetes.io/tls-acme: "true" 31 | path: / 32 | # hosts: 33 | # - chart-example.local 34 | tls: [] 35 | # - secretName: chart-example-tls 36 | # hosts: 37 | # - chart-example.local 38 | secrets: {} 39 | # Optionally specify a set of secret objects whose values 40 | # will be injected as environment variables by default. 41 | # You should add this section to a file like secrets.yaml 42 | # that is explicitly NOT committed to source code control 43 | # and then include it as part of your helm install step. 44 | # ref: https://kubernetes.io/docs/concepts/configuration/secret/ 45 | # 46 | # This creates a secret "mysecret" and injects "mypassword" 47 | # as the environment variable mysecret_mypassword=password. 48 | # mysecret: 49 | # mypassword: password 50 | resources: {} 51 | # We usually recommend not to specify default resources and to leave this as a conscious 52 | # choice for the user. This also increases chances charts run on environments with little 53 | # resources, such as Minikube. If you do want to specify resources, uncomment the following 54 | # lines, adjust them as necessary, and remove the curly braces after 'resources:'. 55 | # limits: 56 | # cpu: 100m 57 | # memory: 128Mi 58 | # requests: 59 | # cpu: 100m 60 | # memory: 128Mi 61 | nodeSelector: {} 62 | 63 | tolerations: [] 64 | 65 | affinity: {} -------------------------------------------------------------------------------- /src/Utils/Microsoft.Solutions.HTTP/HttpClient.cs: -------------------------------------------------------------------------------- 1 | using Flurl.Http; 2 | using Polly; 3 | using Polly.Retry; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using System.Net; 8 | using System.Text; 9 | using System.Threading.Tasks; 10 | 11 | namespace Microsoft.Solutions.HTTP 12 | { 13 | public class HttpClient 14 | { 15 | static HttpClient() 16 | { 17 | policy = BuildRetryPolicy(); 18 | } 19 | 20 | static AsyncRetryPolicy policy; 21 | 22 | public static string ServiceBaseUrl = ""; 23 | 24 | public static async Task GetJsonAsync(string url, string bearerToken = "", object headers = null) 25 | { 26 | return await policy.ExecuteAsync( 27 | () => url 28 | .WithHeaders(new { Accept = "application/json" }) 29 | .WithOAuthBearerToken(bearerToken) 30 | .GetJsonAsync() 31 | ); 32 | } 33 | 34 | public static async Task PostJsonAsync(string url, object data, string bearerToken = "") 35 | { 36 | return await policy.ExecuteAsync(async () => await url 37 | .WithHeaders(new { Accept = "application/json" }) 38 | .WithOAuthBearerToken(bearerToken) 39 | .PostJsonAsync(data) 40 | .ReceiveJson()); 41 | 42 | } 43 | 44 | public static async Task PostJsonAsyncWithHeaders(string url, object data, string bearerToken = "", object headers = null) 45 | { 46 | return await policy.ExecuteAsync(async () => await url 47 | .WithHeaders(headers) 48 | .WithOAuthBearerToken(bearerToken) 49 | .PostJsonAsync(data) 50 | .ReceiveJson()); 51 | 52 | } 53 | 54 | 55 | private static bool IsTransientError(FlurlHttpException exception) 56 | { 57 | int[] httpStatusCodesWorthRetrying = 58 | { 59 | (int)HttpStatusCode.RequestTimeout, // 408 60 | (int)HttpStatusCode.BadGateway, // 502 61 | (int)HttpStatusCode.ServiceUnavailable, // 503 62 | (int)HttpStatusCode.GatewayTimeout // 504 63 | }; 64 | 65 | return exception.StatusCode.HasValue && httpStatusCodesWorthRetrying.Contains(exception.StatusCode.Value); 66 | } 67 | 68 | private static AsyncRetryPolicy BuildRetryPolicy() 69 | { 70 | var retryPolicy = Policy 71 | .Handle(IsTransientError) 72 | .WaitAndRetryAsync(3, retryAttempt => 73 | { 74 | var nextAttemptIn = TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)); 75 | Console.WriteLine($"Retry attempt {retryAttempt} to make request. Next try on {nextAttemptIn.TotalSeconds} seconds."); 76 | return nextAttemptIn; 77 | }); 78 | 79 | return retryPolicy; 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/Utils/Microsoft.Solutions.HTTP/Microsoft.Solutions.HTTP.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net5.0 5 | EAE.Solutions.HTTP 6 | True 7 | EAE.Solutions.HTTP 8 | 0.7.3 9 | Microsoft Solutions 10 | Microsoft Coporation 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/libraries/Microsoft.Solutions.CosmosDB.Security.ManagedIdentity/ConnectionStringAccessor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Azure.Identity; 3 | using Microsoft.Solutions.HTTP; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | 7 | namespace Microsoft.Solutions.CosmosDB.Security.ManagedIdentity 8 | { 9 | public class ConnectionStringAccessor 10 | { 11 | public ConnectionStringAccessor() 12 | { 13 | } 14 | 15 | public static ConnectionStringAccessor Create(string SubscriptionId, string ResourceGroupName, string CosmosDBAccountName) 16 | { 17 | return new ConnectionStringAccessor(SubscriptionId, ResourceGroupName, CosmosDBAccountName); 18 | } 19 | 20 | private string listConnectionStringAPIUrl = string.Empty; 21 | private DefaultAzureCredential azureCredential = null; 22 | 23 | private ConnectionStringAccessor(string SubscriptionId, string ResourceGroupName, string CosmosDBAccountName) 24 | { 25 | // Setup the List Connection Strings API to get the Azure Cosmos DB keys. 26 | listConnectionStringAPIUrl = @$"https://management.azure.com/subscriptions/{SubscriptionId}/resourceGroups/{ResourceGroupName}/providers/Microsoft.DocumentDB/databaseAccounts/{CosmosDBAccountName}/listConnectionStrings?api-version=2021-04-15"; 27 | Console.WriteLine(listConnectionStringAPIUrl); 28 | } 29 | 30 | 31 | /// 32 | /// Retrive Cosmos DB Connection string with ManagedIdentity 33 | /// 34 | /// The ManagedIdentity should have Cosmos DB Account Reader Role 35 | /// CosmosConnectionStrings (ReadWrite / ReadOnly) 36 | public async Task GetConnectionStringsAsync(string ManagedIdentityClientId) 37 | { 38 | azureCredential = new DefaultAzureCredential( 39 | new DefaultAzureCredentialOptions() 40 | { 41 | ManagedIdentityClientId = ManagedIdentityClientId 42 | }); 43 | 44 | var AccessToken = await azureCredential.GetTokenAsync( 45 | new Azure.Core.TokenRequestContext( 46 | new[] { "https://management.azure.com//.default" })); 47 | 48 | var result = await HttpClient.PostJsonAsync(listConnectionStringAPIUrl, string.Empty, AccessToken.Token); 49 | 50 | return new CosmosConnectionStrings() 51 | { 52 | PrimaryReadWriteKey = result.connectionStrings[0].connectionString, 53 | SecondaryReadWriteKey = result.connectionStrings[1].connectionString, 54 | PrimaryReadOnlyKey = result.connectionStrings[2].connectionString, 55 | SecondaryReadOnlyKey = result.connectionStrings[3].connectionString 56 | }; 57 | } 58 | } 59 | 60 | public class CosmosConnectionStrings 61 | { 62 | public string PrimaryReadWriteKey { get; set; } 63 | public string SecondaryReadWriteKey { get; set; } 64 | public string PrimaryReadOnlyKey { get; set; } 65 | public string SecondaryReadOnlyKey { get; set; } 66 | } 67 | 68 | internal class ConnectionStrings 69 | { 70 | public ConnectionString[] connectionStrings { get; set; } 71 | } 72 | 73 | internal class ConnectionString 74 | { 75 | public string connectionString { get; set; } 76 | public string description { get; set; } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/libraries/Microsoft.Solutions.CosmosDB.Security.ManagedIdentity/Microsoft.Solutions.CosmosDB.Security.ManagedIdentity.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net5.0 5 | EAE.Solutions.CosmosDB.Security.ManagedIdentity 6 | True 7 | 0.7.3 8 | Microsoft Solutions 9 | Microsoft Corporation 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | --------------------------------------------------------------------------------