{"id":3370,"date":"2019-08-04T20:34:28","date_gmt":"2019-08-05T03:34:28","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/odata\/?p=3370"},"modified":"2019-08-08T21:44:03","modified_gmt":"2019-08-09T04:44:03","slug":"integrating-cosmos-db-with-odata-part-2","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/odata\/integrating-cosmos-db-with-odata-part-2\/","title":{"rendered":"Integrating Cosmos DB with OData (Part 2)"},"content":{"rendered":"<p>In the first <a href=\"https:\/\/devblogs.microsoft.com\/odata\/integrating-cosmos-db-with-odata-part-1\/\">article<\/a> of this series, we talked about integrating Cosmos DB with ASP.NET Core application powered by OData using a pre-built solution that was using Cosmos Client to run full CRUD operations.<\/p>\n<p>But that&#8217;s not the only way we can work with Cosmos DB from ASP.NET Core &#8211; there are two more approaches that we could follow to work with this great technology.<\/p>\n<p>In this article we are going to leverage the power of the Entity Framework to communicate with Cosmos DB then add OData on top of that to supercharge our API with even more functionality that makes querying, filtering and navigating the data in Cosmos DB even easier and simpler to work with.<\/p>\n<h3 class=\"x-hidden-focus\">Second Approach: Using Entity Framework<\/h3>\n<p>Before we start talking about leveraging the Entity Framework as a technology to communicate with Cosmos DB. It might be useful here to talk a bit about the Entity Framework, what it is, and how to use it with Cosmos DB.<\/p>\n<h4><\/h4>\n<h4>What is the Entity Framework?<\/h4>\n<p>The Entity Framework enables developers to work with data in the form of domain-specific objects and properties, such as students and teachers, without having to concern themselves with the underlying database tables and columns where this data is stored.<\/p>\n<p>&nbsp;<\/p>\n<h4>Setting things up<\/h4>\n<p>Before we start settings things up, I&#8217;m going to assume that you have the following already in place:<\/p>\n<ol>\n<li>An ASP.NET Core API 2.2 project already setup and ready to run (Check this <a href=\"https:\/\/docs.microsoft.com\/en-us\/aspnet\/core\/tutorials\/first-web-api?view=aspnetcore-2.2&amp;tabs=visual-studio\">tutorial<\/a> to learn how to do that)<\/li>\n<li>A Cosmos DB instance already setup with SQL API. (Check our previous <a href=\"https:\/\/devblogs.microsoft.com\/odata\/integrating-cosmos-db-with-odata-part-1\/\">article<\/a> to learn how to do that)<\/li>\n<\/ol>\n<p>Now, in order for us to be able to build a connection between the Entity Framework and Cosmos DB &#8211; we will need to do the following:<\/p>\n<ol>\n<li>Download and install NuGet package <strong>Microsoft.EntityFrameworkCore.Cosmos\u00a0<\/strong>version 2.2.0 in your project.<\/li>\n<\/ol>\n<p>You might need to check the &#8220;include prerelease&#8221; box to be able to find that package since all the releases that are available so far are pre-releases as shown in the following screenshot:<\/p>\n<p><img decoding=\"async\" class=\"aligncenter wp-image-3374 size-full\" src=\"https:\/\/devblogs.microsoft.com\/odata\/wp-content\/uploads\/sites\/23\/2019\/08\/EntityFrameworkCoreCosmos.png\" alt=\"\" width=\"2513\" height=\"1373\" srcset=\"https:\/\/devblogs.microsoft.com\/odata\/wp-content\/uploads\/sites\/23\/2019\/08\/EntityFrameworkCoreCosmos.png 2513w, https:\/\/devblogs.microsoft.com\/odata\/wp-content\/uploads\/sites\/23\/2019\/08\/EntityFrameworkCoreCosmos-300x164.png 300w, https:\/\/devblogs.microsoft.com\/odata\/wp-content\/uploads\/sites\/23\/2019\/08\/EntityFrameworkCoreCosmos-768x420.png 768w, https:\/\/devblogs.microsoft.com\/odata\/wp-content\/uploads\/sites\/23\/2019\/08\/EntityFrameworkCoreCosmos-1024x559.png 1024w\" sizes=\"(max-width: 2513px) 100vw, 2513px\" \/><\/p>\n<p style=\"padding-left: 40px;\">2. Once the package is installed &#8211; let&#8217;s go ahead and setup our DbContext class by creating a two files the model and the context as follows:<\/p>\n<p>This is the Student model class we are working with:<\/p>\n<pre class=\"lang:c# decode:true \">using System;\r\n\r\nnamespace CosmosEFWithOData.Models\r\n{\r\n    public class Student\r\n    {\r\n        public Guid Id { get; set; }\r\n        public string Name { get; set; }\r\n        public int Score { get; set; }\r\n    }\r\n}\r\n<\/pre>\n<p>And this is the DbContext class &#8211; we are going to call it StudentsDbContext:<\/p>\n<pre class=\"lang:default decode:true \">using CosmosEFWithOData.Models;\r\nusing Microsoft.EntityFrameworkCore;\r\n\r\nnamespace CosmosEFWithOData.Brokers\r\n{\r\n    public class StudentsDbContext : DbContext\r\n    {\r\n        public StudentsDbContext(DbContextOptions&lt;StudentsDbContext&gt; options) : base(options)\r\n        {\r\n\r\n        }\r\n\r\n        public DbSet&lt;Student&gt; Students { get; set; }\r\n    }\r\n}\r\n<\/pre>\n<p style=\"padding-left: 40px;\">3. Now let&#8217;s configure our Entity Framework to communicate with our Cosmos DB instance &#8211; in the <em>startup.cs\u00a0<\/em>file, add the following code in your ConfigureServices method:<\/p>\n<pre class=\"lang:default decode:true \">        public void ConfigureServices(IServiceCollection services)\r\n        {\r\n            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);\r\n            services.AddDbContext&lt;StudentsDbContext&gt;(options =&gt;\r\n            {\r\n                options.UseCosmos(\r\n                    serviceEndPoint: \"YOUR_COSMOS_INSTANCE_URL\",\r\n                    authKeyOrResourceToken: \"YOUR_API_KEY\",\r\n                    databaseName: \"studentsdb\");\r\n            });\r\n        }<\/pre>\n<p>You will need to fill in your service endpoint and API key in order for this configuration to succeed, you can find that information by going to your Cosmos DB instance then navigate to the &#8220;Keys&#8221; option on the left hand menu as shows in the following screenshot:<\/p>\n<p><img decoding=\"async\" class=\"aligncenter size-full wp-image-3378\" src=\"https:\/\/devblogs.microsoft.com\/odata\/wp-content\/uploads\/sites\/23\/2019\/08\/CosmosConfigurations.png\" alt=\"\" width=\"1534\" height=\"1188\" srcset=\"https:\/\/devblogs.microsoft.com\/odata\/wp-content\/uploads\/sites\/23\/2019\/08\/CosmosConfigurations.png 1534w, https:\/\/devblogs.microsoft.com\/odata\/wp-content\/uploads\/sites\/23\/2019\/08\/CosmosConfigurations-300x232.png 300w, https:\/\/devblogs.microsoft.com\/odata\/wp-content\/uploads\/sites\/23\/2019\/08\/CosmosConfigurations-768x595.png 768w, https:\/\/devblogs.microsoft.com\/odata\/wp-content\/uploads\/sites\/23\/2019\/08\/CosmosConfigurations-1024x793.png 1024w\" sizes=\"(max-width: 1534px) 100vw, 1534px\" \/><\/p>\n<p>All we need here is the values in the URI and the PRIMARY KEY &#8211; once you get that information, fill in the string in your configuration.<\/p>\n<p style=\"padding-left: 40px;\">4. Once that&#8217;s done &#8211; now let&#8217;s create the controller endpoints that will leverage our Entity Framework and scaffold all CRUD operations endpoints for us.<\/p>\n<p>This can simply be done by right clicking on the controllers folder in your solution, selecting &#8220;Add&#8221; then &#8220;Controller&#8221; then select &#8220;API Controller with actions, using Entity Framework&#8221; then click the &#8220;Add&#8221; button at the bottom of your dialog as shown in the following screenshot:<\/p>\n<p><img decoding=\"async\" class=\"aligncenter wp-image-3380 size-large\" src=\"https:\/\/devblogs.microsoft.com\/odata\/wp-content\/uploads\/sites\/23\/2019\/08\/CreateNewApiControllerWithEF-1024x537.png\" alt=\"\" width=\"640\" height=\"336\" srcset=\"https:\/\/devblogs.microsoft.com\/odata\/wp-content\/uploads\/sites\/23\/2019\/08\/CreateNewApiControllerWithEF-1024x537.png 1024w, https:\/\/devblogs.microsoft.com\/odata\/wp-content\/uploads\/sites\/23\/2019\/08\/CreateNewApiControllerWithEF-300x157.png 300w, https:\/\/devblogs.microsoft.com\/odata\/wp-content\/uploads\/sites\/23\/2019\/08\/CreateNewApiControllerWithEF-768x403.png 768w\" sizes=\"(max-width: 640px) 100vw, 640px\" \/><\/p>\n<p style=\"padding-left: 40px;\">5. Once you click &#8220;Add&#8221; another dialog will pop-up so you can configure which model you would like the API controller to serve, and what DbContext should the controller use to initialize all communication with Cosmos DB &#8211; we will select\u00a0<em>Student\u00a0<\/em>as our model and\u00a0<em>StudentsDbContext\u00a0<\/em>as our context class as shown in the screenshot below:<\/p>\n<p><img decoding=\"async\" class=\"aligncenter wp-image-3382 size-large\" src=\"https:\/\/devblogs.microsoft.com\/odata\/wp-content\/uploads\/sites\/23\/2019\/08\/SelectModelAndContext-1024x399.png\" alt=\"\" width=\"640\" height=\"249\" srcset=\"https:\/\/devblogs.microsoft.com\/odata\/wp-content\/uploads\/sites\/23\/2019\/08\/SelectModelAndContext-1024x399.png 1024w, https:\/\/devblogs.microsoft.com\/odata\/wp-content\/uploads\/sites\/23\/2019\/08\/SelectModelAndContext-300x117.png 300w, https:\/\/devblogs.microsoft.com\/odata\/wp-content\/uploads\/sites\/23\/2019\/08\/SelectModelAndContext-768x299.png 768w, https:\/\/devblogs.microsoft.com\/odata\/wp-content\/uploads\/sites\/23\/2019\/08\/SelectModelAndContext.png 1281w\" sizes=\"(max-width: 640px) 100vw, 640px\" \/><\/p>\n<p style=\"padding-left: 40px;\">6. Once you click &#8220;Add&#8221; Visual Studio will spin up a scaffolding dialog to generate all API methods for all Restful CRUD operations endpoints you would need to communicate with Cosmos DB &#8211; the dialog should look as follows:<\/p>\n<p><img decoding=\"async\" class=\"aligncenter wp-image-3384 size-large\" src=\"https:\/\/devblogs.microsoft.com\/odata\/wp-content\/uploads\/sites\/23\/2019\/08\/ScaffoldingDialog-1024x372.png\" alt=\"\" width=\"640\" height=\"233\" srcset=\"https:\/\/devblogs.microsoft.com\/odata\/wp-content\/uploads\/sites\/23\/2019\/08\/ScaffoldingDialog-1024x372.png 1024w, https:\/\/devblogs.microsoft.com\/odata\/wp-content\/uploads\/sites\/23\/2019\/08\/ScaffoldingDialog-300x109.png 300w, https:\/\/devblogs.microsoft.com\/odata\/wp-content\/uploads\/sites\/23\/2019\/08\/ScaffoldingDialog-768x279.png 768w, https:\/\/devblogs.microsoft.com\/odata\/wp-content\/uploads\/sites\/23\/2019\/08\/ScaffoldingDialog.png 1099w\" sizes=\"(max-width: 640px) 100vw, 640px\" \/><\/p>\n<p style=\"padding-left: 40px;\">7. When the scaffolding and code generation is completed a new class will show up in your Controllers folder with all the CRUD operations already in place and ready to be tested &#8211; to make sure things are running smoothly post a new student to your POST <em>api\/students<\/em> endpoint and then try to retrieve all students using a GET <em>api\/students<\/em> to make sure things are working as expected.<\/p>\n<p>Note: if this is the first time you interact with that Database instance &#8211; I recommend you run the following command to make sure your database exists before running any CRUD operations on it:<\/p>\n<pre class=\"lang:c# decode:true \">await context.Database.EnsureCreatedAsync();<\/pre>\n<p>You can call that line of code in your DbContext class or at the constructor level in your API controller class &#8211; either way you want to make sure the database you&#8217;re interacting with does exist before going any further with this article.<\/p>\n<p>Now that we have completed settings our API up, configured with Entity Framework and Cosmos DB it&#8217;s as easy as 4 lines of code to add OData to our new API, here&#8217;s the steps we will need to follow to accomplish this.<\/p>\n<p>&nbsp;<\/p>\n<h3>OData Integration<\/h3>\n<p>Now that we have implemented and verified our controller endpoint is functional, let&#8217;s do the exact same steps we&#8217;ve done in this <a href=\"https:\/\/devblogs.microsoft.com\/odata\/supercharging-asp-net-core-api-with-odata\/\">article<\/a> to implement OData in our solution.\nI will summarize these steps here as follows:<\/p>\n<ol>\n<li>Add a Nuget package <strong>Microsoft.AspNetCore.OData 7.1.0 <\/strong>to your solution.<\/li>\n<li>Add OData service in your <em>startup.cs<\/em> file, then enable dependency injection along with the functions you want OData to provide through your API.<\/li>\n<li>Here&#8217;s an example of how your\u00a0<em>startup.cs<\/em> file should look:\n<pre class=\"lang:c# decode:true\">using System.Linq;\r\nusing CosmosEFWithOData.Brokers;\r\nusing Microsoft.AspNet.OData.Extensions;\r\nusing Microsoft.AspNetCore.Builder;\r\nusing Microsoft.AspNetCore.Hosting;\r\nusing Microsoft.AspNetCore.Mvc;\r\nusing Microsoft.EntityFrameworkCore;\r\nusing Microsoft.Extensions.Configuration;\r\nusing Microsoft.Extensions.DependencyInjection;\r\n\r\nnamespace CosmosEFWithOData\r\n{\r\n    public class Startup\r\n    {\r\n        public Startup(IConfiguration configuration)\r\n        {\r\n            Configuration = configuration;\r\n        }\r\n\r\n        public IConfiguration Configuration { get; }\r\n\r\n        public void ConfigureServices(IServiceCollection services)\r\n        {\r\n            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);\r\n            services.AddDbContext&lt;StudentsDbContext&gt;(options =&gt;\r\n            {\r\n                options.UseCosmos(\r\n                    serviceEndPoint: \"https:\/\/studentsdb.documents.azure.com:443\/\",\r\n                    authKeyOrResourceToken: \"YOUR_API_KEY\",\r\n                    databaseName: \"studentsdb\");\r\n            });\r\n\r\n            services.AddOData();\r\n        }\r\n\r\n        public void Configure(IApplicationBuilder app, IHostingEnvironment env)\r\n        {\r\n            if (env.IsDevelopment())\r\n            {\r\n                app.UseDeveloperExceptionPage();\r\n            }\r\n            else\r\n            {\r\n                app.UseHsts();\r\n            }\r\n\r\n            app.UseHttpsRedirection();\r\n\r\n            app.UseMvc(routeBuilder =&gt;\r\n            {\r\n                routeBuilder.EnableDependencyInjection();\r\n                routeBuilder.Select().Filter().Expand().OrderBy();\r\n            });\r\n        }\r\n    }\r\n}\r\n<\/pre>\n<\/li>\n<li>Your controller\u00a0<em>StudentsController.cs\u00a0<\/em>should look as follows:\n<pre class=\"lang:c# decode:true \">using Microsoft.AspNetCore.Mvc;\r\nusing CosmosEFWithOData.Brokers;\r\nusing CosmosEFWithOData.Models;\r\nusing Microsoft.AspNet.OData;\r\nusing System.Linq;\r\n\r\nnamespace CosmosEFWithOData.Controllers\r\n{\r\n    [Route(\"api\/[controller]\")]\r\n    [ApiController]\r\n    public class StudentsController : ControllerBase\r\n    {\r\n        private readonly StudentsDbContext context;\r\n\r\n        public StudentsController(StudentsDbContext context)\r\n        {\r\n            this.context = context;\r\n        }\r\n\r\n        \/\/ GET: api\/Students\r\n        [HttpGet]\r\n        [EnableQuery()]\r\n        public ActionResult&lt;IQueryable&lt;Student&gt;&gt; GetStudents()\r\n        {\r\n            return context.Students;\r\n        }\r\n    }\r\n}\r\n<\/pre>\n<\/li>\n<li>Let&#8217;s verify our new endpoint with OData integration by hitting an endpoint like:\n<pre class=\"lang:default decode:true\">http:\/\/localhost:36442\/api\/students?$select=name<\/pre>\n<p>And your response should look as follows:<\/p>\n<pre class=\"lang:default decode:true\">[\r\n    {\r\n        \"Name\": \"Hassan Habib\"\r\n    },\r\n    {\r\n        \"Name\": \"Josh McCall\"\r\n    },\r\n    {\r\n        \"Name\": \"Roberto Bortolussi\"\r\n    },\r\n    {\r\n        \"Name\": \"Cody Allen\"\r\n    },\r\n    {\r\n        \"Name\": \"Daniel Lin\"\r\n    }\r\n]<\/pre>\n<\/li>\n<\/ol>\n<p>By seeing this result, we verified OData is functional on your API retrieving and processing data from your Cosmos DB instance container using the Entity Framework.\nIn the next article, we will discuss working with OData and Cosmos DB without needing to build an API &#8211; stay tuned! \ud83d\ude42<\/p>\n<p>&nbsp;<\/p>\n<h3>Final Notes<\/h3>\n<ol>\n<li>You can download the solution I used to run this demo from <a href=\"https:\/\/github.com\/hassanhabib\/ODataWithCosmosDbAndEF\">here<\/a> (Don&#8217;t forget to update the endpoint &amp; key values in <em>startup.cs<\/em> file).<\/li>\n<li>The package I&#8217;m using to run OData is of <strong>Microsoft.AspNetCore.OData 7.1.0\u00a0<\/strong>I ran into some issues using August release of the same library (7.2.0) I will communicate with our OData team and update this post accordingly.<\/li>\n<li>I highly recommend following this <a href=\"https:\/\/docs.microsoft.com\/en-us\/azure\/cosmos-db\/\">link<\/a> to learn more about Cosmos DB and it&#8217;s capabilities.<\/li>\n<li>Once more, huge thanks to Cosmos DB team for providing such a great documentation around such powerful technology.<\/li>\n<li>I also highly recommend staying up-to-date with all the new updates in Cosmos DB by following this <a href=\"https:\/\/azure.microsoft.com\/en-gb\/blog\/tag\/cosmos-db\/\">link<\/a> to their blog.<\/li>\n<\/ol>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In the first article of this series, we talked about integrating Cosmos DB with ASP.NET Core application powered by OData using a pre-built solution that was using Cosmos Client to run full CRUD operations. But that&#8217;s not the only way we can work with Cosmos DB from ASP.NET Core &#8211; there are two more approaches [&hellip;]<\/p>\n","protected":false},"author":3348,"featured_media":3345,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1,117],"tags":[],"class_list":["post-3370","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-odata","category-webapi"],"acf":[],"blog_post_summary":"<p>In the first article of this series, we talked about integrating Cosmos DB with ASP.NET Core application powered by OData using a pre-built solution that was using Cosmos Client to run full CRUD operations. But that&#8217;s not the only way we can work with Cosmos DB from ASP.NET Core &#8211; there are two more approaches [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/odata\/wp-json\/wp\/v2\/posts\/3370","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/odata\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/odata\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/odata\/wp-json\/wp\/v2\/users\/3348"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/odata\/wp-json\/wp\/v2\/comments?post=3370"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/odata\/wp-json\/wp\/v2\/posts\/3370\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/odata\/wp-json\/wp\/v2\/media\/3345"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/odata\/wp-json\/wp\/v2\/media?parent=3370"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/odata\/wp-json\/wp\/v2\/categories?post=3370"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/odata\/wp-json\/wp\/v2\/tags?post=3370"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}