From 26dc136c7e7e3779d0e276f326252d23561c8a3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Lachowski?= Date: Wed, 17 Jun 2026 08:55:30 +0200 Subject: [PATCH] RDBTC-221 Migrate Technical Guides: RDBTC-14 Simple Crud Operations --- ...vendb-and-asp-net-core-8-application1.webp | Bin 0 -> 15128 bytes ...ravendb-and-asp-net-core-8-application.mdx | 313 +++++++++++++++++- 2 files changed, 309 insertions(+), 4 deletions(-) create mode 100644 guides/assets/simple-crud-operations-with-ravendb-and-asp-net-core-8-application1.webp diff --git a/guides/assets/simple-crud-operations-with-ravendb-and-asp-net-core-8-application1.webp b/guides/assets/simple-crud-operations-with-ravendb-and-asp-net-core-8-application1.webp new file mode 100644 index 0000000000000000000000000000000000000000..ea8bf9266bf67d750d581e8b4c961227b1a5cd3c GIT binary patch literal 15128 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 literal 0 HcmV?d00001 diff --git a/guides/simple-crud-operations-with-ravendb-and-asp-net-core-8-application.mdx b/guides/simple-crud-operations-with-ravendb-and-asp-net-core-8-application.mdx index d2bc0fd2bb..87ab8c4c20 100644 --- a/guides/simple-crud-operations-with-ravendb-and-asp-net-core-8-application.mdx +++ b/guides/simple-crud-operations-with-ravendb-and-asp-net-core-8-application.mdx @@ -1,9 +1,314 @@ --- -title: "Simple CRUD operations with RavenDB and ASP.NET Core 8 application" -tags: [querying, asp-net, getting-started] -description: "Read about Simple CRUD operations with RavenDB and ASP.NET Core 8 application on the RavenDB.net news section" -external_url: "https://ravendb.net/articles/simple-crud-operations-with-ravendb-and-asp-net-core-8-application" +title: "Simple CRUD Operations with RavenDB and ASP.NET Core 8" +tags: [asp-net, csharp, getting-started] +description: "Learn how to scaffold a minimal API with ASP.NET Core 8 and wire up create, read, update, and delete document operations against a RavenDB database." published_at: 2025-03-31 image: "https://ravendb.net/wp-content/uploads/2025/03/crud-operations-asp_net-article-cover.jpg" +see_also: + - title: "Storing Entities" + link: "client-api/session/storing-entities" + source: "docs" + path: "Client API > Session" + - title: "Loading Entities" + link: "client-api/session/loading-entities" + source: "docs" + path: "Client API > Session" + - title: "Deleting Entities" + link: "client-api/session/deleting-entities" + source: "docs" + path: "Client API > Session" +author: "Paweł Lachowski" proficiency_level: "Beginner" --- + +import Admonition from '@theme/Admonition'; +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +import CodeBlock from '@theme/CodeBlock'; +import LanguageSwitcher from "@site/src/components/LanguageSwitcher"; +import LanguageContent from "@site/src/components/LanguageContent"; +import Image from "@theme/IdealImage"; + +## Introduction + +Preparing basic CRUD operations can be a helpful base for your next steps when building an ASP.NET app that uses RavenDB as storage. This article will create a simple app connected to a database. It will be an app for managing movies. We'll provide you with a basic understanding of how ASP.NET and RavenDB can interact. So, let's see how to do that. + +## Prerequisites + +Prerequisites are the same as in the article "[How to setup RavenDB with ASP.NET Core 8 application](./how-to-setup-ravendb-with-asp-net-core-8-application)": + +* [.NET SDK](https://learn.microsoft.com/en-us/dotnet/core/install/) installed on your machine. This article uses 8.0.403 +* [Database in RavenDB](https://ravendb.net/cloud) + +If you encounter any problems with prerequisites, please refer to the article linked [here](./how-to-setup-ravendb-with-asp-net-core-8-application). + +## Setup + +As mentioned in the prerequisites, for the sake of simplicity, we will use code from the previous [article](./how-to-setup-ravendb-with-asp-net-core-8-application) combined with boilerplate code. + +Let's prepare the base of our code - add the generated part. First, install the scaffolding tool if you haven't already: + +``` +dotnet tool install -g dotnet-aspnet-codegenerator +``` + +Then add the required package: + +``` +dotnet add package Microsoft.VisualStudio.Web.CodeGeneration.Design +``` + +After the command finishes, create a new file called `Movie.cs` in your directory. This file will hold our new class, the template for our new *documents* in the RavenDB database. Add the following code to it: + +```csharp +namespace YourDirectoryName +{ + public class Movie + { + public required string Id { get; set; } + public required string Title { get; set; } + } +} +``` + +The code above gives us a class with two properties: an ID and the movie's title. Of course, you can add more - release dates or ratings from websites like IMDb. + +Now, this allows us to use terminal commands to generate some code instead of writing it ourselves. We can now use the following command to generate code for us: + +``` +dotnet aspnet-codegenerator minimalapi -e MovieEndpoints -m YourDirectoryName.Movie -o +``` + +Now that our machine has done most of our work, let's clean this up. We will use this code differently than the previous article, so we must remove a few elements, unnecessary mapgets, and the employee class at the bottom (a sample entity copied from RavenDB's built-in sample data). After cleaning MapGet and class on the bottom, you should have something resembling this: + +```csharp +using System.Security.Cryptography.X509Certificates; +using Raven.Client; +using Raven.Client.Documents; +using Your_Directory_Name; + +var builder = WebApplication.CreateBuilder(args); + +builder.Services.AddEndpointsApiExplorer(); +builder.Services.AddSwaggerGen(); + +var app = builder.Build(); + +if (app.Environment.IsDevelopment()) +{ + app.UseSwagger(); + app.UseSwaggerUI(); +} + +string serverURL = "https://your_RavenDB_server_URL"; +string databaseName = "your_database_name"; +string certificatePath = @"C:\path_to_your_pfx_file\cert.pfx"; + +var x509Certificate = new X509Certificate2(certificatePath); + +IDocumentStore documentStore = new DocumentStore +{ + Urls = new[] { serverURL }, + Database = databaseName, + Certificate = x509Certificate +}; +documentStore.Initialize(); + +app.MapMovieEndpoints(); + +app.Run(); +``` + +Let's modify this code so it works with the rest of the template part. Let's start with DocumentStore. The exact part that you need to change is `IDocumentStore documentStore = new DocumentStore` and credentials input below. Remember that if you use a local server, you may want to delete the certificate depending on your configuration. We need to provide it as a dependency injection so we can use it in other parts of our code; let's change it to: + +```csharp +builder.Services.AddSingleton(provider => { + var store = new DocumentStore + { + Urls = new[] { serverURL }, + Database = databaseName, + Certificate = x509Certificate + }; +``` + +To make it all work, you must add `return store;` with the builder at the end so that will work. We also need to lower the swagger part, so cut it or delete it from above and paste our code. It should look similar to that: + +```csharp + return store; +}); + +var app = builder.Build(); + +if (app.Environment.IsDevelopment()) +{ + app.UseSwagger(); + app.UseSwaggerUI(); +} +``` + +All those parts are essential and can't be skipped; alternatively, you can copy the code below. In case of using our ready code, **just remember to change:** + +* `using YourDirectoryName` +* `serverURL` +* `databaseName` +* `certificatePath` (if you are using it, unsecured local RavenDB doesn't need it) + +```csharp +using YourDirectoryName; +using System.Security.Cryptography.X509Certificates; +using Raven.Client; +using Raven.Client.Documents; + +var builder = WebApplication.CreateBuilder(args); + +builder.Services.AddEndpointsApiExplorer(); +builder.Services.AddSwaggerGen(); + +string serverURL = "http://127.0.0.1:8080"; +string databaseName = "XYZ"; + +builder.Services.AddSingleton(provider => { + var store = new DocumentStore + { + Urls = new[] { serverURL }, + Database = databaseName, + }; + store.Initialize(); + return store; +}); + +var app = builder.Build(); + +if (app.Environment.IsDevelopment()) +{ + app.UseSwagger(); + app.UseSwaggerUI(); +} + +app.MapMovieEndpoints(); + +app.Run(); +``` + +With this ready, we can continue coding our operations. To code those, we will use our generated *MovieEndpoints.cs* file. Inside, **you need to add** `using Raven.Client.Documents;` to gain access to RavenDB functions in this file. Also, if you are using new files for it then you need to have the NuGet package installed before proceeding further. + +``` +dotnet add package RavenDB.Client +``` + +You can delete existing endpoints and add those presented below, or you can just edit existing ones. + +## Operations + +We divided this text into sections so you can quickly find what you need in a moment. In all cases, we will be using *DocumentStore*. [DocumentStore](/7.2/client-api/what-is-a-document-store) is the base for all RavenDB actions. It communicates with your cluster and can handle multiple databases. Having only a single instance of *DocumentStore* is essential to maintaining a single definition of connection to your database. + +### Create + +With everything else ready, let's create some documents. To create a new *document,* we will use the following code: + +```csharp +group.MapPost("/", async (Movie model, IDocumentStore store) => +{ + using var session = store.OpenAsyncSession(); + await session.StoreAsync(model); + await session.SaveChangesAsync(); + return Results.Created($"/api/Movie/{model.Id}", model); +}) +.WithName("CreateMovie") +.WithOpenApi(); +``` + +Let's unravel this code. Let's start with global explanations that apply to all those examples. We must use map methods to specify the route for all those endpoints. Meanwhile, we inject our *DocumentStore* and add a document using a [DocumentSession](/7.2/client-api/session/what-is-a-session-and-how-does-it-work) to our connected database. The following line immediately creates a movie object using our class as a template. Then, our object is saved and returned to us so we know it was made. We close the endpoint, and then we can continue testing this. + +If you use `dotnet run` and open your local server with `/swagger` appended to the URL, expand the POST endpoint, click **Try it out**, then click **Execute**. You can modify the `Id` field to create documents with different IDs. Create a few movies before moving on. + +Swagger UI showing the Create endpoint test + +### Read + +Now that you created your new *document,* we need to read it. To do that, you can use this code: + +```csharp +group.MapGet("/", async (IDocumentStore store) => +{ + using var session = store.OpenAsyncSession(); + return Results.Ok(await session.Query().ToListAsync()); +}) +.WithName("GetAllMovies") +.WithOpenApi(); +``` + +As you can see above, we again use *DocumentStore,* but this time to get information from our database using the route we establish with MapGet. Next, we open the session and return all our movies. This allows us to see if our previously created movies were created correctly. As you can see, DocumentStore and Session repeat in each code example, so I will skip explaining those in future examples. + +### Update + +Let's create a short function to update the document we just read. To update your *document,* you can use the following code: + +```csharp +group.MapPut("/{id}", async (string id, Movie input, IDocumentStore store) => +{ + using var session = store.OpenAsyncSession(); + var movie = await session.LoadAsync(id); + if (movie == null) + { + return Results.NotFound(new { Message = "Movie not found" }); + } + movie.Title = input.Title; + await session.SaveChangesAsync(); + return Results.NoContent(); +}) +.WithName("UpdateMovie") +.WithOpenApi(); +``` + +This endpoint loads the document by ID, replaces its title with the value from the request body, then calls [`SaveChangesAsync`](/7.2/client-api/session/saving-changes) to flush the change and returns a 204 No Content response. + +### Read by ID + +Now let's verify the document changed correctly, this time fetching it by ID. The following code does the job: + +```csharp +group.MapGet("/{id}", async (string id, IDocumentStore store) => +{ + using var session = store.OpenAsyncSession(); + var movie = await session.LoadAsync(id); + return movie != null ? Results.Ok(movie) : Results.NotFound(); +}) +.WithName("GetMovieById") +.WithOpenApi(); +``` + +This code uses `LoadAsync` to load the document with the matching ID and return it as a `Movie` object. If no document with that ID exists, `LoadAsync` returns null and we respond with 404 Not Found. + +### Delete + +After you successfully tested all other operations, it's time to test the delete option. To do this, you can use the following snippet: + +```csharp +group.MapDelete("/{id}", async (string id, IDocumentStore store) => +{ + using var session = store.OpenAsyncSession(); + var movie = await session.LoadAsync(id); + if (movie == null) + { + return Results.NotFound(new { Message = "Movie not found" }); + } + session.Delete(movie); + await session.SaveChangesAsync(); + return Results.Ok(new { Message = "Movie deleted successfully" }); +}) +.WithName("DeleteMovie") +.WithOpenApi(); +``` + +Once again, we load the document, check if it exists, and proceed with `session.Delete(movie)`, which marks it for deletion. Calling `SaveChangesAsync` flushes that deletion to the server and we return a confirmation message. + +Now, you can run your application and check those operations yourself. Remember to run RavenDB in the background because those will not work without it. This gives you a basic understanding of how to add CRUD to your application. + +## Summary + +This guide walked through scaffolding a minimal ASP.NET Core 8 app and implementing full CRUD operations against a RavenDB database using `DocumentStore` and `DocumentSession`. + +- Register `IDocumentStore` as a singleton so the application shares a single connection across all requests, which is required for correct cluster communication and connection pooling. +- Each CRUD operation opens a short-lived session, performs its work, then calls `SaveChangesAsync` to flush changes as a single atomic batch to the server. +- `LoadAsync` returns null when the document is not found, so always check for null before operating on the result to avoid null reference exceptions at runtime.