.NET 5 is finally out ππ₯³ and it comes with lots of interesting new features that make software development easier, faster and better. In this article, we will focus on ASP.NET Web API.
Developing RESTful API using .NET has really improved over the years from ASP.NET MVC to ASP.NET Core and now .NET 5.
Every major release has come with great features that make developing RESTful API better. With .NET 5, it just got a whole lot easier and better by allowing you to focus more on your business logics and creating an Endpoint with few lines of code.
With .NET 5, you can configure your API to automatically make use of the OpenAPI Support and generate Swagger Docs with just the check of a box (no single line of code is required from you). Isn't it amazing?
To demonstrate this, we will create an Employee management system that will be used to Create, Read, Update and Delete an Employee's record.
The code for this sample can be found on the CloudBloq/EmployeeManagement repository on GitHub.
The technology used in this article are:
Prerequisites
Creating the Database
We will make use of CockroachDb to store the data. You can download CockroachDb from here.
After starting a cluster in insecure mode, we need to connect an SQL shell to the cluster in insecure mode. In the SQL Shell, create a database employee by running:
CREATE DATABASE employee;
Next, point the SQL shell to the newly created database by running:
USE employee;
Next, create a table employee
CREATE TABLE employee(
Id UUID PRIMARY KEY DEFAULT gen_random_uuid(), name STRING, department STRING, email STRING
);
The gen_random_uuid() is used to tell the DB that if we don't pass in a unique and valid UUID/GUID, it should generate one for us automatically.
Finally, we will insert a row into the table:
INSERT INTO employee (name, department, email) VALUES ('Test', 'Computer Science', 'Test@gmail.com');
You can check the data in the table by running:
SELECT * FROM employee;
Create the Solution and Projects
We will need an ASP.NET Web API project that will define the endpoints.
After opening VS, click the Create a new project link and select the ASP.NET Core Web Application, give the project a name Employee.API and the solution a name EmployeeManagement:
click Create
Next, select the ASP.NET Core Web API and verify that the check box labelled Enable OpenAPI support is checked (see image below):
click Create.We will make use of a Class Library to define our Database Entity and data access codes. Add a new Class Library (.NET Standard) to the solution named Employee.DataAccess
Install Dependencies
- We need to install the Npgsql.EntityFrameworkCore.PostgreSQL package. This package will be used to communicate with the database. To install the package, right click the solution in the solution explorer and select Manage NuGet Packages for Solution. Under the Browse section, search for Npgsql.EntityFrameworkCore.PostgreSQL and click on it, then in the preview panel, select the Employee.API and Employee.DataAccess checkbox so it will be installed only into the projects Employee.API and Employee.DataAccess and click the Install button:
- We need to add a reference for project Employee.DataAccess to Employee.API. To do this, right click the Dependencies and click Add project Reference, select the Employee.DataAccess checkbox and click ok.
The Employee Entity
We will make use of EntityFrameworkCore as the ORM. Entities (classes) are used to define the database objects (tables) and those entities are mapped to the database table in the DbContext.
Create a folder called Model in the Employee.DataAccess project, and in that folder add a new class file called Employee.cs. The naming of this class/entity(Employee.cs) doesn't need to match with the table name(employee), but the property used to map the entity with the table in the DbContext must match. The code in the Employee.cs is:
Four properties (id, name, department and email) are defined to represent the four columns in the employee table.
The [Key] attribute on line 9 is used to specify that the property id is the primary key of the Entity, while the [DatabaseGenerated(DatabaseGeneratedOption.Identity)] attribute on line 10 tells EntityFramework that the value of the primary key will be generated by the database if the User doesn't provide a value.
The [Required] attribute defined on lines 13, 16 and 19 is used to specify that the name, department and email fields are required when sending an Employee's data to the Server via Create or Update; if any of the three is missing, the data for that employee won't be stored in the database.
The [EmailAddress] attribute tells EntityFramework that the value in the email field must be a valid email address.
If you are confused right now, I assure you that after we are done and we run the application, you will see how everything fits into the big picture.
Defining the DbContext
The DbContext class is an integral part of Entity Framework. It is used to perform most of the database configurations needed. Add a C# file to the Model folder called EmployeeManagementDBContext.cs:
Line 11 define a property (employee) of type DbSet<> which is used to map the Employee object to the employee table. The name of this property must match with the table name else an error will occur. The data in the employee table can now be accessed and manipulated through this property.
Accessing the Data
Create a new folder called Repository in the project Employee.DataAccess. Next, create an interface called IEmployeeDAO.cs:
Line 9 defines the GetAll method which will be used to return a list of all the Employees in the database. Line 13 defines the GetEmployeeById method which takes in the id as a parameter and returns the Employee with that id if one exists. Line 11 defines the CreateEmployee method which takes in a new Employee and adds it to the database. Line 15 defines the method UpdateEmployee which takes in an Employee and updates that record in the database only if the Employee exists in the database.
The delete method is left as an assignment for you, but I will explain what you need to do.
Next, we will create a concrete class EmployeeDAO.cs that will implement the IEmployeeDAO.cs interface which will then provide implementations to the methods. In the same Repository folder, create a C# class called EmployeeDAO.cs:
Line 12 defines a field dbContext of type EmployeeManagementDBContext. Through this field, we can access the employee property hence get access to the employee table data.
At this point you might be wondering that we haven't added the database connection string to the EmployeeManagementDBContext, but worry not. We will add it in a more secured file in Employee.API. Won't we have to write another set of logics to read the connection string since it will be in a different project? Not at all! One thing you should understand is that at runtime, i.e. when we call an endpoint, the Employee.API will be the entry point of the Http request. At that point, all other libraries (Employee.DataAccess in this case) that are being used by the Employee.API are also executed under the same Http request hence if those libraries need any configuration settings, and such settings aren't present in the library itself but present in the entry point (Employee.API), it will be gotten automatically from the entry point project. Confused? Don't worry. When we get to the Employee.API, you will understand better.
Lines 38 to 41 provide the implementation to the GetAll method. When we call the property employee of EmployeeManagementDBContext, we get back an object that implements the IQueryable and Enumerable interface. Hence, we are able to run some Linq query against the result. As you can see on line 40, we called the employee and converted the result to a list using the ToList() function. It can be broken down as:
var employeeDbResult = dbContext.employee;
return employeeDbResult.ToList();
The first line calls the employee property which we then apply the ToList() function on in the second line to convert the result to a List. Those 2 lines of code perform the same function as line 40.
Lines 26 to 36 provide an implementation to the GetEmployeeById method. We will ensure the id isn't null from the controller before sending it to this method so there is no need to check for null or empty values again here. After calling the employee property, we use the FindAsync(id) method to get the Employee with that id on line 28, then we return the Employee only if it exists.
Lines 19 to 24 provide the implementation to the CreateEmployee method. The API Controller will validate the Employee object before passing it to this method so there is no need to validate the input here again. We use the AddAsync() method on line 21 to add the new Employee to the database but take note that the database won't be updated until we save the changes as shown on line 22.
Lines 43 to 65 provide the implementation to the UpdateEmployee method. We check if the Employee exists in the database on line 45 before proceeding. Lines 49 to 57 are used to detach the entity before we update. The entity is being tracked due to line 45 hence, if we try updating it without detaching it first, we will get an error. We set the State of the Entity to Modified on line 59 hence notifying EntityFramewoke that the value(s) of that particular Employee has(have) been modified. We update the database and save the changes on lines 61 and 62.
With this, we are done with the data access code. Now we will move to the Employee.API project to create our endpoints.
Creating the Endpoints
First, we need to perform some configurations. Replace the code in the Startup.cs file with:
Lines 15, 38 to 42 and 54 are used to enable CORS on the endpoint. Line 36 is used to define the implementation of IEmployeeDAO interface that should be used during dependency injection which we specified as EmployeeDAO .
Lines 34 and 35 define the database configuration that should be used. It looks for the connection string named EmployeeManagementDBContext (this name can be anything else) from either the appsettings.json file, secrets.json file or Environment variable. It searches for the parameter EmployeeManagementDBContext from either of those 3 locations. We will be making use of the appsettings.json to store it. Replace the code in the appsettings.json with:
Next, add a new empty API controller to the Controllers folder, name it EmployeeController.cs. Replace the code in this file with:
We injected an instance of IEmployeeDAO through the constructor on lines 16 to 20.
Lines 57 to 65 define the action method GetAll which responds to the request GET /Employee used to get all the Employees.
Lines 41 to 54 define the action method GetById which responds to the request GET /Employee/{id} to get a particular Employee.
Lines 23 to 38 define the action method Create which responds to the request POST /Employee to create a new Employee.
Lines 68 to 79 define the action method Update which responds to the request PUT /Employee to update an Employee.
For the delete functionality, in the IEmployeeDAO.cs file add another method that returns a Task named DeleteEmployee which takes in the id of the Employee to delete. Add the implementation of this method to the EmployeeDAO.cs.
First thing to do in this method is to get the Employee by calling the GetEmployeeById(id), then use the .Remove(employeeObjectTodelete) on the dbContext.employee property to delete the employee and then save the changes to the database.
Next, in the EmployeeController.cs, create an action method Delete that takes in the id and marks it with the attribute [HttpDelete] then passes the id into the DeleteEmployee of IEmployeeDAO.cs and that is it.
Running the Application
Right-click the solution and click Build Solution. After Build is successful, click CTRL + f5 to run the application. If you have followed all the steps carefully, you shouldn't get any errors. Once the application starts running, you should get the image below in your browser:
Isn't it amazing that Swagger docs are generated automatically for all our endpoints. We don't need Postman or other tools to test the endpoints again. We can do everything we need to do inside the browser now.
Click the GET /api/Employee then click the Try it out button and Execute. You should get back the initial Employee we created earlier, alongside other Employees you created, if you did.
Click the POST /api/Employee then Try it out, you should get:
You can edit the details of the id, name, department and email. If you remove the id field, the database will auto generate a unique id. If you pass in an invalid id, the record won't be stored instead, you will get an error message. If you pass in a valid id that already exists in the database, you will get an error message stating that. If you remove either of the name, department or email field and Execute it you will get back an error stating that the missing field is required due to the [Required] attribute used on them. If the value of the email isn't a valid email, you will get back a response saying "The email field is not a valid e-mail address". If all went well, when you click the Execute button you should get back the newly created Employee.
Try the PUT /api/Employee. For this, you will need to copy one of the Employees from the GET /api/Employee and update any of the values except the id then Execute it.
Try out the GET /api/Employee/{id} too.
Whoa! We have come to the end of this tutorial. This is not the end of your learning, there are still lots of things to learn e.g. Authentication, Authorization, MiddleWare etc. Those are advanced topics. Trust me when I say you are done with the basis. With the knowledge you just gained, you can develop a RESTful API that any mobile, web or desktop application can use.
Awesome! Please share it with anyone you think could use this information. Thanks for reading. As always, if you have any questions, comments, or concerns about this post, feel free to leave a comment below.
Top comments (5)
This blog was really great, never seen a great blog like this before. I think Iβm going to share this with my friends.
espirittech.com/dot-net-applicatio...
Thank you always for well written apt tutorials. Reading your article made me better understand how it all works on. Net 5 especially when you registered the Cors. Moreover, what is the purpose of registering the Cors? I will code along all the above and revert if I have bugs. Can you write on authentication, authorization and Middlewares please?
I also noticed that you didn't talk about how you came about the ILogger object and we didn't use it in the application! Why is this so?
Hi, thanks for reading the article and leaving a comment.
If you plan to consume your ASP.NET Core API from another project you must enable CORS in the API project. docs.microsoft.com/en-us/aspnet/we.... should help you understand what CORS is all about.
docs.microsoft.com/en-us/aspnet/co... will help with understanding how logging works in ASP.NET Core
What is the place or use case of Automapper and the Data Transfer Object entity classes?
Hi, thanks for reading the article and leaving a comment. I didn't make use of Automapper in this project. c-sharpcorner.com/article/integrat... can help you understand how to make use of Automapper, If you have any questions feel free to drop a comment, thanks.