In this article, we are going to do a small demo on AspNetCore 6 Web API CRUD operations.
Step 2:
What Is Web API:
Web API is a framework for building HTTP services that can be accessed from any client like browser, mobile devices, desktop apps.In simple terminology API(Application Programming Interface) means an interface module that contains a programming function that can be requested via HTTP calls to save or fetch the data for their respective clients.
Some of the key characteristics of API:
- Supports HTTP verbs like 'GET', 'POST', 'PUT', 'DELETE', etc.
- Supports default responses like 'XML' and 'JSON'. Also can define custom responses.
- Supports self-hosting or individual hosting, so that all different kinds of apps can consume it.
- Authentication and Authorization are easy to implement.
- The ideal platform to build REST full services.
Create A .NET6 Web API Application:
Let's create a .Net6 Web API sample application to accomplish our demo. We can use either Visual Studio 2022 or Visual Studio Code(using .NET CLI commands) to create any.Net6 application. For this demo, I'm using the 'Visual Studio Code'(using the .NET CLI command) editor.
CLI command
dotnet new webapi -o Your_Project_Name
dotnet new webapi -o Your_Project_Name
Now let's explore default services or middleware that are in 'Program.cs':
Services in Program.cs:
builder.Services.AddControllers(); builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen();
- (Line:1) The 'AddControllers' service for API Controllers. This method will not work for the Views or Pages.
- (Line: 2) The 'AddEndpointsApiExplorer' service for endpoint metadata.
- (Line: 3) The 'AddSwagerGen' service for the Swagger.
if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(); } app.UseHttpsRedirection(); app.UseAuthorization(); app.MapControllers();
- (Line: 3-4) The swagger middleware to load the swagger page.
- (Line: 6) The 'UseHttpsRedirection' middleware to redirect the 'HTTP' request to 'HTTPS'.
- (Line: 7) The user authorization middleware.
- (Line: 8) The 'MapControllers' is an endpoint middleware that can direct the request to API's controllers.
SQL Query To Create A Sample Table:
Run the below command to create a sample table.
CREATE TABLE [dbo].[Cake] ( [Id] INT IDENTITY (1, 1) NOT NULL, [Name] VARCHAR (MAX) NULL, [Price] DECIMAL (18, 2) NULL, [Description] VARCHAR (MAX) NULL );
Entity Framework Core:
Entity Framework Core is an Object/Relational Mapping(ORM) framework. EF Core makes database communication more fluent and easy. The 'DatabaseContext' class acts as a database from our c# code, it will contain all registered tables as 'DbSet<TEntity>'(TEntity is any POCO class of a table).
In this demo, we are going to implement the 'Code First With Existing Database' technique. Creating the classes for an existing database is known as 'Code First With Existing Database'.
Install Entity Framework Core NuGet:
Now install the Entity Framework Core NuGet.
Package Manager Command
Install-Package Microsoft.EntityFrameworkCore -Version 6.0.1
Install-Package Microsoft.EntityFrameworkCore -Version 6.0.1
.Net CLI Command
dotnet add package Microsoft.EntityFrameworkCore --version 6.0.1
dotnet add package Microsoft.EntityFrameworkCore --version 6.0.1
Now install SQLServer which is Entity Framework Core dependent library.
Package Manager Command
Install-Package Microsoft.EntityFrameworkCore.SqlServer -Version 6.0.1
Install-Package Microsoft.EntityFrameworkCore.SqlServer -Version 6.0.1
Package Manager Command
dotnet add package Microsoft.EntityFrameworkCore.SqlServer --version 6.0.1
dotnet add package Microsoft.EntityFrameworkCore.SqlServer --version 6.0.1
Setup Entity Framework Core DatabaseContext:
Let's create a class that represents our table. So let's create folders like 'Data' and subfolder like 'Entities' and then add a class like 'Cake.cs'.
Data/Entities/Cake.cs:
namespace Dot6.API.Crud.Data.Entities; public class Cake { public int Id { get; set; } public string Name { get; set; } public decimal Price { get; set; } public string Description { get; set; } }To manage or control all the table classes we have to create DatabaseContext class. So let's create our context class like 'MyWorldDbContext.cs' in the 'Data' folder.
Data/MyWorldDbContext.cs:
using Dot6.API.Crud.Data.Entities; using Microsoft.EntityFrameworkCore; namespace Dot6.API.Crud.Data; public class MyWorldDbContext : DbContext { public MyWorldDbContext(DbContextOptions<MyWorldDbContext> options) : base(options) { } public DbSet<Cake> Cake { get; set; } }
- (Line: 6) The 'Microsoft.EntityFrameworkCore.DbContext' needs to be inherited by our 'MyWorldDbcontext' to act as a Database context class.
- (Line: 8) The 'Microsoft.EntityFrameworkCore.DbContextOptions' is instance of options that we are going to register in 'Program.cs' like 'ConnectString', 'DatabaseProvider', etc.
- (Line: 12) All our table classes must be registered inside of our Database context class with 'DbSet<T>' so that the entity framework core can communicate with the table of the database.
appsettings.Development.json:
"ConnectionStrings":{ "MyWorldDbConnection":"your_connection" }Register the Database Context service in the 'Program.cs' file for dependency injection.
Program.cs:
builder.Services.AddDbContext<MyWorldDbContext>(options => { options.UseSqlServer(builder.Configuration.GetConnectionString("MyWorldDbConnection")); });
Create A Sample API Controller:
In Web APIs controllers are the entry point for the HTTP requests. The 'Action' methods are logical units in the controller which get executed and return the response per request.
Now create a sample API controller like 'CakeController.cs' inside of the 'Controllers' folder.
Controllers/CakeController.cs:
using Dot6.API.Crud.Data; using Microsoft.AspNetCore.Mvc; namespace Dot6.API.Crud.Controllers; [ApiController] [Route("[controller]")] public class CakeController: ControllerBase { private readonly MyWorldDbContext _myWorldDbContext; public CakeController(MyWorldDbContext myWorldDbContext) { _myWorldDbContext = myWorldDbContext; } }
- (Line: 6) Decorated with the 'ApiController' attribute indicates that a type and all derived types(controllers) are used to server HTTP API responses. Controller decorated with this attribute is configured with features and behavior targets at improving the developer experience for building APIs
- (Line: 7) Route to define our URL. The default expression '[Controller]' means name of the controller(eg: 'Cake'). We can define the custom name as the route that can be different from the controller name also.
- (Line: 8) Our C# class to become a controller it needs to inherit 'Microsoft.AspNetCore.Mvc.ControllerBase'.
- (Line: 10-14) Injected our DatabasContext into the controller.
Read Operation:
Let's create an Action method(which is a logical unit of the controller) of HTTP GET requests. Our job our action method to read the data from the database.
Controllers/CakeController.cs:
[HttpGet] public async Task<IActionResult> GetAsync() { var cakes = await _myWorldDbContext.Cake.ToListAsync(); return Ok(cakes); }
- Here we can observe there is no 'Route[]' attribute defined on the action method. If our controller contains a single HTTP Get action method it is optional to add the 'Route[]' attribute. By convention, API will return the response. But if we have multiple action methods of the same HTTP types like 'GET', 'POST', 'PUT', 'Delete' then we have to define routes per action method explicitly.
- (Line: 1) The 'HttpGet' attribute represents that our action method gets invoked for HTTP GET requests.
- (Line: 2-6) Defined an asynchronous action method to return the collection of data.
- (Line: 4) Fetching all records from the 'Cake' entity as an async call. The 'ToListAsync' is an extension from 'Microsoft.EntityFrameworkCore'.
- (Line: 5) The 'Ok()' method creates an OkObjectResult, object that produces an StatusCodes.Status200Ok(which means 200 success) response.
Step1:
Let's create an action method for the HTTP POST request. Our action method job is to create a new record into the database.
Controllers/CakeController.cs:
[HttpGet] [Route("get-cake-by-id")] public async Task<IActionResult> GetCakeByIdAsync(int id) { var cake = await _myWorldDbContext.Cake.FindAsync(id); return Ok(cake); } [HttpPost] public async Task<IActionResult> PostAsync(Cake cake) { _myWorldDbContext.Cake.Add(cake); await _myWorldDbContext.SaveChangesAsync(); return Created($"/get-cake-by-id?id={cake.Id}", cake); }
- (Line: 9) The 'HttpPost' attribute represents our action method only gets invoked for the HTTP POST requests.
- (Line: 10-15) Asynchronous action method for creating the new record.
- (Line: 12) The 'Add' method on database context begins tracking the given entity. This will update the state of the database context as 'EntityState.Added' which means data is ready to save into the database.
- (Line: 13) The 'SaveChangesAsync()' method saves our data into the database.
- (Line: 14) The 'Created()' method creates a CreatedResult object that produces a status code of 201(created) as a response. This 'Created()' method first parameter will be URL for endpoint where we can get the newly created record, so to generate this URL I have created another HTTP GET action method at(Line: 1-7) that fetches data by the 'id' value. If you want you can use the 'Ok()' method as a return type from the HTTP POST action method as well.
Step1:
Step 2:
Step3:
Step4:
Update Operation:
Let's create an action method for the HTTP PUT requests. Our action method job is to update the record.
Controllers/CakeController.cs:
[HttpPut] public async Task<IActionResult> PutAsync(Cake cakeToUpdate) { _myWorldDbContext.Cake.Update(cakeToUpdate); await _myWorldDbContext.SaveChangesAsync(); return NoContent(); }
- (Line: 1) The 'HttpPut' represents our action method that gets invoked for HTTP PUT requests.
- (Line: 2-7) Asynchronous method for updating the records.
- (Line: 4) The 'Update()' method changes the Database context state as changed, which means data is ready to update. The 'Update()' method will update all columns for the record so make sure this is the case for the update or not. If you try to pass only a few columns of data then the remaining columns get updated with their default values. One more thing to remember the object should contain 'Id'(primary key) with value.
- (Line: 5) The 'SaveChangesAsyn()' method saves the data into the database.
- (Line: 6) The 'NoContent()' method creates a 'NoContentResult' object that produces an empty of status code 204(no content) as response.
Now run the application and test our HTTP PUT endpoint.
Step1:
Step2:
Step3:
Step4:Delete Operation:
Let's create an action method of HTTP Delete request. Our action method job is to delete a particular(eg: by 'id' value) record from the database.
Controllers/CakeController.cs:
[Route("{id}")] [HttpDelete] public async Task<IActionResult> DeleteAsync(int id) { var cakeToDelete = await _myWorldDbContext.Cake.FindAsync(id); if (cakeToDelete == null) { return NotFound(); } _myWorldDbContext.Cake.Remove(cakeToDelete); await _myWorldDbContext.SaveChangesAsync(); return NoContent(); }
- (Line: 1) The '[Route]' attribute defined that means 'id' value should be passed as part of URL, and the '{}' is expression means any string defined inside of it will be the input parameter to the action method.
- (Line: 2) The 'HttpDelete' attribute represents our action method getting invoked only for the HTTP Delete methods.
- (Line: 3-13) Asynchronous action method for deleting the record from the database.
- (Line: 5) Fetching the record that needs to be deleted from the database.
- (Line: 6-9) Validating the record to be deleted. If no valid record in the database then we return the 'NotFound()' method whose status code is '404'.
- (Line: 10-11) Removing the record from the database context. The 'SaveChangeAsync()' update the database context changes to the database.
- (Line: 12) The 'NoContent()' status code is '204'.
Now run the application and test our HTTP DELETE endpoint.
Step1:
Step:2
Step3:
Support Me!
Buy Me A Coffee
PayPal Me
Video Session:
Wrapping Up:
Hopefully, I think this article delivered some useful information on .NET6 Web API CRUD operations. I love to have your feedback, suggestions, and better techniques in the comment section below.
Great Article!! Thanks.
ReplyDeleteExcellent Article with Crystal clear explanation
ReplyDeleteGreat and Helpful! Thanks Dude
ReplyDeleteExcelente artÃculo!muchas gracias
ReplyDeleteHI I am having an error "System.InvalidOperationException: Unable to resolve service for type 'WebAPILab.Data.DataContext' ... " I did declared the service and reviewed everything, can you give me some help... thank you
ReplyDeleteHow to show privew withou first name and last name only get vlaues like john deo
ReplyDelete