Migrating ASP.NET to Azure Cosmos DB w/ GitHub Copilot | Sergiy Smyrnov | Azure Cosmos DB Conf 2026
Microsoft Developer
0:07 Hello, welcome to my session from JOIN to JSON,
0:11 migrating the real world ASP.NET application
0:13 to Azure Cosmos DB with GitHub Copilot.
0:16 My name is Sergiy Smyrnov.
0:17 I am principal PM in Azure Cosmos DB team.
0:21 Normally, migrating relational databases and applications using relational
0:26 databases to NoSQL is naturally a hard problem.
0:31 Today we're going to talk about, example,
0:34 how to use GitHub Copilot with Cosmos DB agent kit to accelerate the journey.
0:40 We're to take a sample e-commerce workload based
0:43 on the SQL Server Adventure Works LT schema,
0:47 which is a popular sample schema in SQL Server,
0:52 which has more than 10 tables with complex joins consisting from customers,
0:59 products, categories, tags, and sales orders.
1:04 And on top of it, we're going to make it a little more challenging.
1:07 to add the actual application running along with it.
1:10 For that, we're to use Azure Samples
1:12 Adventure Works application published a long time ago.
1:14 uh And along with GitHub Copilot, we're going to use Cosmos DB Agent Kit.
1:21 ah What is Cosmos DB Agent Kit?
1:24 Cosmos DB Agent Kit is open source collection of AI
1:28 skills we built to work across GitHub Copilot, Cloud Code,
1:31 and other agent skills, compatible tools,
1:34 and CLIs to help with those complex tasks
1:37 to design data model from relational to NoSQL,
1:40 choose the right partition key, do the query optimization,
1:43 apply SDK best practices when we convert application,
1:47 and validate all the information we pass along as part of the process.
1:52 This is a link to our Cosmos DB agent kit, which is published in open source.
1:57 You're welcome to use it.
1:58 You're welcome to contribute it.
2:01 Now let's go to live demo.
2:03 I'm not going to bore you with slides.
2:04 We're going to just actually show you how to do it end to end.
2:07 So for that, I'm going to show, I mentioned the AdventureWorks uh application.
2:11 This is a link to that application.
2:14 What I did, I cloned that application to my local workstation.
2:18 uh And then on top of it,
2:21 I installed our Cosmos DB agent kit, which is an open source repo.
2:25 And the installation is very simple.
2:27 All you have to do is copy NPX skills
2:30 at Cosmos DB agent kit locally and install it.
2:35 have choices to install it to local project or globally.
2:39 So let's dive right in to our environment.
2:44 This is a local clone of the application.
2:46 ah I already pre-installed agent kit uh in my environment, agent kit skills.
2:54 You can see that I installed skills here.
2:57 All it did is it's created the dot
3:00 agents subdirectory in my environment with skills,
3:03 Cosmos DB best practices and uh created a rules folder.
3:07 This is pretty much a secret sauce of all
3:10 the brain power of Cosmos DB best practices knowledge
3:14 packaged in a small reusable skills dot MD format
3:17 for each skill type with the prefixes by category.
3:21 And those rules will be used by GitHub Copilot as part of our workflow.
3:27 Along with that, we've added a couple of things
3:31 to help GitHub Copilot to add a structure to the process.
3:36 First thing is we've created step-by-step prompts,
3:40 which does show the navigation process of what to ask Copilot at each stage.
3:48 Like if we break the application
3:51 modernization and data migration project in phases,
3:55 and also what specific outcomes or artifacts each phase need to produce.
3:59 For example, in phase one,
4:02 we produce migration assessment prompt with specific outcomes,
4:05 migration assessment uh MD file, and XS parents and volume metrics.
4:10 Those two are actually very critical to next phases because a lot of times,
4:17 converting relational schema and relational application
4:20 to NoSQL database like Cosmos require
4:23 knowledge of both access patterns and volumetrics to ensure that we pick
4:28 the right partition key and align uh queries and access patterns to access
4:33 patterns actually used in the application
4:36 and not just derive it and hallucinate.
4:38 uh For that, we created two template files
4:42 to fill those access patterns and volumetrics in the files.
4:47 The volumetric template here is uh Very simple.
4:55 uh We basically define in the schema table row counts, average row size,
5:01 some gross projected rate,
5:03 uh and project some read-write TPS with examples of the nodes.
5:08 And this is sample schema, just basically uh use feed this to copilot
5:13 to populate it based on the actual data samples.
5:17 you can then, because it's an empty file, you can actually come back and uh
5:22 update those details based on your business knowledge.
5:26 The iAccessParents template is similar structure,
5:28 but it has a little different details.
5:36 where we break the read patterns and write patterns separately,
5:40 and we annotate them with R and W for simplicity.
5:45 And then we define the pattern name,
5:47 define which tables participate in pattern names,
5:50 obviously for reads in relational world, could be multiple tables for join,
5:54 define the filter lookup fields, and then again, define the frequency TPS,
5:59 along with some latency requirements and additional notes.
6:03 Same thing for writes and if there
6:05 is any additional notes about like transactional consistency,
6:07 we can put it at the bottom.
6:09 So those two will fit into our workflow to produce additional details.
6:16 Now, uh if we look into our flow of our step-by-step prompts,
6:22 ah we basically have seven prompts.
6:25 First one is create migration assessment report.
6:29 Second one is...
6:31 do schema and access pattern conversion plan.
6:34 This is what will produce actual Cosmos DB data model.
6:39 Then uh prompts three and four are created
6:41 based on the final data model we produce.
6:44 uh We create infrastructure as a code
6:48 samples for Azure deployment as infra biceps.
6:51 Here you can plug in like Terraform for example,
6:55 if your company is doing Terraform deployments
6:57 uh or any other commands for deployments.
7:00 We specify some uh specific parameters for actual deployment like Azure region,
7:06 your account name, database name,
7:08 add principal ID for entry ID deployments or anything else.
7:12 Next step is actually deploying validates
7:15 that deployment is successful on Azure.
7:17 Or if you test in locally in uh container emulator, you can substitute it.
7:23 uh Prompt-Fi would be converting data to JSON based on the data model.
7:30 uh pre-join aggregates and then do the loading into Cosmos.
7:34 created as a data migration, basically build data migration pipeline.
7:38 ah Here for our simplicity,
7:40 we use CSV because our sample data is in CSVs for that simple demo,
7:46 but you can build EDF pipeline, can build Spark notebooks,
7:50 uh anything is possible once you have the mappings of the source and target.
7:53 uh Prompt 6 is based on the...
7:57 assessment and schema conversion, create application conversion plan.
8:02 This is where we're to take it beyond database itself.
8:04 We can actually analyze the application code,
8:08 analyze controllers, analyze methods, analyze classes, uh services,
8:12 and create a detailed plan for actual application conversion.
8:17 You can see that we've identified a few things here before to shorten the cycle,
8:23 that .NET conversion for Cosmos DB, has a Newton soft JSON dependency.
8:28 need to make sure that we account for this, update Cosmos client builder,
8:32 namespace, et cetera, and clean up some reference with the errors or warnings.
8:37 And final step is execute application diversion.
8:41 I've pre-created a lot of the steps all the way through step seven.
8:45 We're gonna go into details to look what the outcomes of those steps exist.
8:50 But for now, I wanna kick off the prompt seven.
8:54 In the prompts, folder.
8:57 And while it's running, we're going to review some of the outcomes.
8:59 So while it's turning away, we're actually going to see ah what's happening.
9:04 So let me copy and paste the prompts here.
9:11 And we're going to ask Copilot.
9:13 So as of right now, the only thing is
9:18 done is uh analyzing my SQL script DDL schema,
9:22 analyze sample files, uh analyze the application itself.
9:26 You see that in the models, uh views, controllers, everything is still original.
9:32 We have not changed actual application code.
9:34 All we've done is we've done a bunch of assessments and we
9:39 created the folders here for actual for actual uh data conversion.
9:45 And we've created infra code to load data in.
9:47 ah So now we're actually going to trigger the application migration plan here.
9:53 So this is my prompt, follow the final schema and access
9:56 pattern conversion plan and application conversion plan,
9:59 rewrite the application to Cosmos DB NoSQL,
10:01 start application, run API validation tests.
10:04 And I define three clear success criteria goals.
10:07 Successful build, application start successfully, return local URL,
10:11 and do API validation test successfully.
10:15 And then at end, we're to return the URL for manual UI validation.
10:17 I'm going to do it live at the end.
10:19 So let's kick it off.
10:26 While it's running, let's do...
10:30 a quick review of the outcomes in the earliest steps I walked through.
10:39 So the first step produce assessment.
10:49 So let's look outcomes of the assessment.
10:52 So in the assessment,
10:55 it recognized that, it analyzed that schema has 12 tables across two schemas,
11:03 sales of T and DBO, whereas migration availability is pretty high.
11:10 It mapped the application technology stack,
11:13 recognized that it has pretty old .NET Core 2.1 with ASP, .NET, and VC.
11:19 using entity framework, using SQL Server database and some front end.
11:24 uh It started doing the initial uh entity relational summary,
11:29 ah identifying key database features to use uh and start
11:34 doing data model analysis and propose some Cosmos DB container design.
11:40 So initially it's created container, let me allows this in this workspace.
11:48 um It started proposing some initial container
11:51 design with customer IDs, a partition key,
11:54 some unique key policies, and start stepping out some nest adjacent models.
11:59 uh Same thing for products and categories.
12:01 uh And identifying access pattern methods.
12:05 Then after that, we went to uh next steps, schema and access patterns.
12:13 And in that step, we...
12:17 We went little further.
12:18 We went really, really deep into container strategy, document models,
12:23 partition key design to start analyzing
12:26 our populated access patterns and volumetrics produced
12:29 from the templates based on those assessments
12:33 to annotating uh all the in-scope entities.
12:36 uh Based on the assessment, actually told it to remove the DBO.
12:41 uh tables because of what two tables which not related
12:45 to application that were related to some DBA structures for deployments,
12:49 which we do not really want to carry over to ah Cosmos NoSQL.
12:54 We put it in autoscope.
12:55 We excluded build version error log uh for metadata
12:58 uh because normally in like when we modernize application,
13:02 we actually want to move it as a database
13:05 and move it to like application insights or Azure Monitor.
13:08 um We define what's app monetization scope is.
13:12 We actually told it to add sales order controller as a new
13:17 controller because while we have the tables for sales orders,
13:20 we should not have any operational controllers in the application itself.
13:24 So we're doing application modernization as part of this migration project.
13:29 And then we uh finalize our container strategy design.
13:33 This is where you actually can iterate on the process.
13:37 uh Initially, it was uh separating customers and orders,
13:41 but because we uh we see that customers and orders
13:44 share the same partition key based on the access patterns.
13:47 We actually have uh benefit in NoSQL Cosmos DB,
13:52 combine them together uh and preserve atomic batch consistency
13:57 for create order plus patch order count in one transaction.
14:02 And we eliminate in complexity,
14:04 which require cross-container processors using change feed.
14:08 So we can see that there was design decision,
14:12 with Veridex, YWill, and a change feed combined.
14:15 And the final design is actually presented here.
14:17 So this is the final container layout where we
14:20 have customer orders container with partition key customer ID,
14:24 and then products container with partition key category ID.
14:27 Both have different dock types.
14:28 This is one of the best practices and benefits of Cosmos DB,
14:33 which allow you to store uh different entities,
14:36 ah which share the same partition key.
14:39 and discriminate them by document type
14:41 in the same container for efficiencies on application.
14:46 Um.
14:49 So let's continue.
14:50 So this is the final document model where we have customer ID ah as ID.
14:56 We're going to actually tell it
14:58 to preserve original IDs for backward compatibility.
15:01 But we're going to add prefix IDs for IDs
15:04 to maintain uniqueness for uh each customer ID.
15:07 And we're going to remove row ID from the processing.
15:10 So this schema X patterns is pretty
15:13 much continue with all the details, mapping columns.
15:16 You can see that row GUID is actually
15:18 excluded because We replaced it with Cosmos ID.
15:21 We denormalized it like nested addresses as they embedded JSON, ah et cetera.
15:28 Same thing for sales orders, similar pattern, continuous along with that.
15:37 uh Next thing is actually.
15:42 uh We've created the bicep files.
15:46 I already mentioned this.
15:48 It's pretty simple.
15:49 uh Bicep file will edit.
15:52 One of the benefits of Cosmos DB was bicep files.
15:54 We've replaced everything with entry ID and we simply grant you,
16:00 like for my demo, I'm granting two entry ID roles here.
16:07 A Cosmos DB operator role and Cosmos data contributor role.
16:10 to ensure that I can create containers and also
16:13 I can do data plan operations in Infraspace and then.
16:16 uh We, as part of the data migration,
16:23 we create data migration subfolder with converting data to a JSON file.
16:28 This is pretty much the processing of the data
16:32 for customers and also pre-processing data for sales orders here.
16:37 Let's go little further.
16:42 Yeah, this is one of the sales orders.
16:46 They also share the same customer ID partition key, but IDs or prefix order ID.
16:53 And very similar to products and product categories.
16:56 And those two files actually loaded to Cosmos
17:01 DB using the load to Cosmos DB Python script.
17:07 And this is the same thing you can actually telco pilot to convert into Again,
17:12 any ATL tools you plan to use for migration,
17:16 you can use the same logic to generate the migration scripts.
17:21 This is actually how it looks in Cosmos DB.
17:24 While the uh application conversion is processing,
17:27 we can quickly look on what's happening in Cosmos DB.
17:31 ah So my biceps script created a Cosmos DB account with following...
17:38 uh following database, adwkslt, with two containers,
17:43 customer orders and products, just like we've seen it created.
17:49 Those containers also have created custom index
17:52 policies based on all those access patterns,
17:56 which include paths, and then we exclude everything else.
18:00 And it also recognized that for some access patterns,
18:03 we need composite indexes based on type,
18:06 like last name, first name, for different order and...
18:09 ah capabilities.
18:11 So it's pretty smart and very similar to do for products.
18:15 ah is uh documents, examples already preloaded to Cosmos DB for our validation.
18:24 So we've pre-migrated the data, same documents for products.
18:27 ah And we have categories as well further down here.
18:37 And if we go back to our code, let's see where we are.
18:40 We are pretty close ah to finish.
18:45 Let's quickly watch, kind of like revert back, what it done with the code.
18:52 This is a prompt we submitted for final application changes.
18:58 You can see that it started reviewing the files and allies conversion plans.
19:03 When it got the full context, it's...
19:05 ah ah define what needs to be updated,
19:10 start updating with a project file, then went to update the...
19:14 ah document model documents for customer sales order products.
19:23 We write as a program files to update
19:26 the startup to change the F core to Cosmos DB.net.
19:29 um Created the new controller files.
19:34 um Looks like there was some errors in it.
19:40 It actually went ahead and uh find a different approach.
19:47 ah And finally, successful here.
19:52 I was waiting for me to accept.
19:55 This is where it's changing the layout.
19:58 Now it arrived to our goal one.
19:59 Build succeeded with zero errors.
20:01 means that we achieved the goal one.
20:02 Let's start with the application, start and validation.
20:06 So it started the application, home page returned 200 successful.
20:09 So it's actually, so it looks like it's troubleshooting some issues here.
20:19 And one of the issues it's reporting is actually related
20:23 to some limitations in serverless
20:25 to support the full functionality for deployment.
20:28 And it's just going through some troubleshooting cycles.
20:31 While it's doing, we can quickly review ah what it's done in the service.
20:40 So if we collapse our documentation a little bit, let's review.
20:48 the controllers.
20:49 this is, it updated the controllers with Cosmos DB actions.
20:58 Like you can see that updated Cosmos exceptions to get it
21:03 to catch the status codes from Cosmos DB ah for models.
21:08 It's pretty simple.
21:09 m Most of them are Similar, we've added some e-tagging for our JSON
21:18 property ID to replace and update models.
21:26 services are also pretty, like I think we look at it,
21:31 but this is the example of where it's
21:34 ah reusing the Cosmos client from the client builder,
21:39 getting the DB name, container name um from Cosmos client.
21:44 And then basically for each query definition,
21:49 basically defining Cosmos DB query, uh iterating on the results like here,
21:57 we get in the list and then ah
22:00 this is a pagination has more results, for example.
22:03 Here for product by ID,
22:05 this would be uh called what we call a point read in Cosmos DB.
22:09 We actually use in...
22:10 ah Container read item async where we supply an ID and a partition key.
22:19 This is a fastest way to read data in Cosmos DB because
22:23 partition key and ID always give you a unique pointer to a document.
22:26 You can see that it's point read,
22:30 what we call one RU for small documents and so on.
22:36 It updated the views based on changes we
22:40 submitted to the project and in the program itself.
22:46 You can see that it's adding the Singleton Cosmos Client
22:50 builder with serialized option ah for camel case and direct mode.
22:55 It's pretty simple.
22:57 And we are using the Entry ID for our connectivity, basically.
23:06 Let's see where we are with actual project.
23:15 All right.
23:15 Looks like our application is successfully
23:18 started and all the API checks validated.
23:21 um Let's quickly look at the application
23:24 itself to validate that everything is running.
23:27 um This is our application running on Cosmos DB.
23:33 You can see that we've updated the view
23:37 to have view links to all the main controllers.
23:41 We have categories.
23:42 We can actually look at the products.
23:44 We can look at the customers and sales orders.
23:47 ah If we want to see the details about the sales orders,
23:51 we can go inside and see the details.
23:53 So this pretty much concludes the demo part.
23:56 uh Let's go into final closing key takeaways.
24:05 As we look through the demo, I want to highlight a few important uh points
24:11 to consider when you use Copilot for migration modernization projects.
24:16 uh One thing that is important is structure your prompts as a pipeline.
24:21 uh Each step should be built on the output of the previous
24:25 one or consider multiple previous steps to feed into the next iteration.
24:29 And then let Copilot do automatic discovery and you act as a judge.
24:35 uh Second point, inject domain knowledge
24:39 the schema design step and review iterative needed.
24:42 ah Converting relational schema to NoSQL a lot
24:48 of times may require multiple ah iterations.
24:53 So use copilot uh prompts to create a first iteration and then be a judge
24:59 and a challenger to challenge it
25:02 to analyze and create alternatives and explain why.
25:05 And then if you feed the details, from the templates,
25:09 which is my next step is templates guide quality.
25:13 If you provide the real life value metrics
25:16 from your real application and access pattern details,
25:20 ah they will result in a better quality and consistent output with more
25:25 accurate conversion model and will count
25:28 for scalability risks and avoid over-engineering.
25:30 And the final uh detail to take home
25:33 is generate a plan before executing, review the plan.
25:37 ah As a checkpoint, before actual destructive rewrite,
25:41 it will save time and allow you to iterate quickly with less rework.
25:47 This is an example where we generate the prompt
25:50 6 before executing prompt 7 for actual application conversion.
25:54 You can find converted repository example and my prompt by prompt
26:01 instruction templates at aka.ms slash rdbms to Cosmos DB prompts.
26:06 A link it will...
26:08 link you to my sample repo in the document folder,
26:11 will find the templates files and prompt by prompt document sample.
26:16 Thank you for watching and happy coding.