Building and Testing a .NET API: A Step-by-Step Guide

In this blog, I will show you how to create a .NET API, host it locally using Docker, and integrate it with a web application. We'll use Visual Studio Code as our primary development environment. This guide includes everything from setting up the environment to testing the API on a web application, making it perfect for beginners.

Note: I was working on a Mac during this project, which is why I chose Docker to containerize and host the API. Docker provides a consistent runtime environment that works across operating systems like macOS, Linux, and Windows, ensuring my API behaves the same on all platforms.

Prerequisites

Before we begin, ensure you have the following tools installed:

Visual Studio Code Extensions

  1. C#: For IntelliSense, debugging, and running .NET applications.

  2. Docker: To manage Docker containers directly in VS Code.

  3. SQL Server (mssql): For querying and managing the database with Azure Data Studio.

Step 1: Setting Up the .NET API

  • Open your terminal and navigate to the directory where you want to create the project.

  • Run the following command to create a new .NET API project:

      dotnet new webapi -n MyApiProject
    
  • Navigate into the project folder:

      cd MyApiProject
    
  • Restore dependencies and run the project:

      dotnet restore
      dotnet run
    
  • The API will now be running locally at http://localhost:5000 (or https://localhost:5001 for HTTPS).

Set Up Debugging in VS Code

  • Go to the Run and Debug tab and click on "Create a launch.json file."

  • Select .NET. Use the following configuration to enable debugging:

      {
        "version": "0.2.0",
        "configurations": [
          {
            "name": ".NET Core Launch (web)",
            "type": "coreclr",
            "request": "launch",
            "preLaunchTask": "build",
            "program": "${workspaceFolder}/bin/Debug/net5.0/MyApiProject.dll",
            "cwd": "${workspaceFolder}",
            "serverReadyAction": {
              "action": "openExternally",
              "pattern": "\\bNow listening on: (https?://\\S+)"
            },
            "env": {
              "ASPNETCORE_ENVIRONMENT": "Development"
            }
          }
        ]
      }
    

Step 2: Adding Dapper for Database Operations

Install Dapper
Run the following command to install Dapper via NuGet:

dotnet add package Dapper

Create a Data Access Class

  • Add a new folder named Data in your project.

  • Create a class for handling database operations, such as:

      using Dapper;
      using System.Data.SqlClient;
    
      public class MyDataAccess
      {
          private readonly string _connectionString;
    
          public MyDataAccess(string connectionString)
          {
              _connectionString = connectionString;
          }
    
          public IEnumerable<MyModel> GetAllData()
          {
              using (var connection = new SqlConnection(_connectionString))
              {
                  return connection.Query<MyModel>("SELECT * FROM MyTable");
              }
          }
      }
    

Define the Model

  • Add a folder named Models and create a class for the model:

      public class MyModel
      {
          public int Id { get; set; }
          public string Name { get; set; }
      }
    

Step 3: Setting Up Azure Data Studio

  • Open Azure Data Studio and connect to your server.

  • Create a New Database:

    • Right-click on the Databases node and select New Database.

    • Name it MyDatabase.

  • Create a Table:

    • Right-click on the Tables node and select New Table.

    • Add columns, such as Id (int) and Name (varchar).

    • Save the table.

Adding Sample Data to the Database

After creating the database and tables in Azure Data Studio, you can insert sample data using SQL queries or programmatically through your .NET API.

Insert Data Using SQL Queries in Azure Data Studio

  1. Open Azure Data Studio and connect to the database.

  2. Right-click on your database (e.g., MyDatabase) and select New Query.

  3. Write and execute an INSERT query to add sample data to the table. For example, if your table is named MyTable with columns Id and Name, you can use the following query:

     INSERT INTO MyTable (Id, Name)
     VALUES 
     (1, 'John Doe'),
     (2, 'Jane Smith'),
     (3, 'Alice Johnson');
    

    This will insert three sample records into the table.

  4. Verify the Data: Run a SELECT query to ensure the data was added successfully:

     SELECT * FROM MyTable;
    

    You should see the inserted rows in the query results.

Alternative: Use a Database Seeder in Your API Code (Optional)

If you prefer, you can programmatically add the data from your .NET API by writing a database seeder function. This function would connect to the database and execute the necessary INSERT statements.

Example in C#:

using System.Data.SqlClient;

public class DatabaseSeeder
{
    private readonly string _connectionString;

    public DatabaseSeeder(string connectionString)
    {
        _connectionString = connectionString;
    }

    public void Seed()
    {
        using (var connection = new SqlConnection(_connectionString))
        {
            connection.Open();
            var query = @"
                INSERT INTO MyTable (Id, Name) VALUES (1, 'John Doe');
                INSERT INTO MyTable (Id, Name) VALUES (2, 'Jane Smith');
                INSERT INTO MyTable (Id, Name) VALUES (3, 'Alice Johnson');
            ";
            var command = new SqlCommand(query, connection);
            command.ExecuteNonQuery();
        }
    }
}

You can call this Seed method during the startup of your application to populate the database with sample data.

Where is the Data Being Sent from the API?

The data you’ve inserted into the database is fetched by the .NET API through the Dapper query defined in your data access class (MyDataAccess). The GetAllData() method sends a SELECT query to the database and retrieves the rows you’ve inserted.

Example in C#:

public IEnumerable<MyModel> GetAllData()
{
    using (var connection = new SqlConnection(_connectionString))
    {
        return connection.Query<MyModel>("SELECT * FROM MyTable");
    }
}

This retrieved data is then exposed via an API endpoint and consumed by the React.js application. The API acts as a bridge between the database and the frontend, allowing the React.js application to access and display the data dynamically. Which we will create later as we finish with the API.

Step 4: Containerizing with Docker

Create a Dockerfile
In the root of your project, create a file named Dockerfile with the following content:

FROM mcr.microsoft.com/dotnet/aspnet:5.0 AS base
WORKDIR /app
EXPOSE 80

FROM mcr.microsoft.com/dotnet/sdk:5.0 AS build
WORKDIR /src
COPY ["MyApiProject/MyApiProject.csproj", "MyApiProject/"]
RUN dotnet restore "MyApiProject/MyApiProject.csproj"
COPY . .
WORKDIR "/src/MyApiProject"
RUN dotnet build "MyApiProject.csproj" -c Release -o /app/build

FROM build AS publish
RUN dotnet publish "MyApiProject.csproj" -c Release -o /app/publish

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "MyApiProject.dll"]

Build the Docker Image
Run the following command in the terminal:

docker build -t myapiproject:latest

Run the Docker Container
Start the container:

docker run -d -p 8080:80 --name myapicontainer myapiproject:latest

Your API will now be available at http://localhost:8080.

Building a web application is essential to test and showcase the functionality of the .NET API effectively. While the API handles data and operations, it requires a user-friendly interface to make the data accessible and interactive. I chose to showcase the API through a web application to demonstrate its real-world use and validate that the endpoints work correctly by integrating it into a practical scenario. React.js was my framework of choice for this project because I have prior experience working with it, which allowed me to create a responsive and visually appealing frontend efficiently. React’s component-based architecture and seamless integration with APIs made it an ideal choice for dynamically fetching and displaying the data. By combining my knowledge of React.js with the power of the .NET API, I created a full-stack application that highlights both the backend's capabilities and the frontend's user-centric design.

Step 5: Creating the Web Application with React.js

  1. Set Up a New React Project

    • Open the terminal and run the following commands to create a React.js project using create-react-app:

        npx create-react-app my-web-app
        cd my-web-app
      
  2. Install Axios for API Requests

    • Axios is a popular library for making HTTP requests in React. Install it by running:

        npm install axios
      
  3. Create a Component to Fetch Data from the API

    • Inside the src folder, create a new file called ApiData.js and add the following code:

        import React, { useState, useEffect } from 'react';
        import axios from 'axios';
      
        const ApiData = () => {
          const [data, setData] = useState([]);
      
          useEffect(() => {
            // Fetch data from the .NET API
            axios.get('http://localhost:8080/api/data')
              .then(response => {
                setData(response.data);
              })
              .catch(error => {
                console.error('Error fetching data:', error);
              });
          }, []);
      
          return (
            <div>
              <h1>Data from .NET API</h1>
              <ul>
                {data.map((item, index) => (
                  <li key={index}>{item.name}</li>
                ))}
              </ul>
            </div>
          );
        };
      
        export default ApiData;
      
  4. Integrate the Component into Your App

    • Open the App.js file and replace the default content with:

        import React from 'react';
        import ApiData from './ApiData';
      
        function App() {
          return (
            <div>
              <ApiData />
            </div>
          );
        }
      
        export default App;
      
  5. Start the React Application

    • Run the React app using:

        npm start
      
  6. Open http://localhost:3000 in your browser. The app should display data fetched from the .NET API.

Conclusion

In this project, we demonstrated how data is seamlessly fetched from a .NET API and displayed in a React.js web application. The .NET API acts as the backend, handling data operations and serving it through endpoints. Using Axios, the React.js application makes HTTP requests to these API endpoints, retrieves the data, and dynamically renders it on the frontend. This process ensures real-time interaction, where any changes in the backend data can be immediately reflected in the user interface. By combining the strengths of the .NET API for robust backend logic and React.js for a responsive and dynamic frontend, we created a fully functional full-stack application that bridges the gap between data handling and user experience.

You can find the complete code for the .NET API in my GitHub repository:

https://github.com/shahidsha1612/DapperApiDemo.git