DEV Community

Blake Lamb
Blake Lamb

Posted on

Creating a C# Web API

Overview

Setting up a Web API using C#/.NET is pretty easy, setting up endpoints and connecting to a database can be more difficult. This article will go through the process of how to accomplish those tasks using vsCode.

Setup

Download the .NET SDK

In order to run a .NET Web API, the .NET SDK has to be downloaded. This is pretty easy, just click here for the official download page.

Create A Sandbox App

Now that the SDK is installed, open up a run a new instance of vsCode and navigate in the command line to the folder where the API will live. Once there, use the command dotnet new webapi. Once that has completed running, the WebApi has been created. I will walk through a few more setup steps before we get into the rest of the API work.

Installs

These are some required and some useful extensions to have downloaded in vsCode:

  • c# by Microsoft (Required)
  • NuGet Package Manager by jmrog/li>
  • Visual Studio IntelliCode by Microsoft

Now that these have been installed, run dotnet add package MongoDB.Driver

Set a port for the WebApi to run on

Find the launchSettings.json file in your root folder and open it. Locate the line with the application name, then below that, find the line that says applicationUrl. Change this line to whatever url you would like it to run on. I have mine set to run on localhost:4000.

// launchSettings.json

"daily_debrief.API": {
  "commandName": "Project",
  "dotnetRunMessages": "true",
  "launchBrowser": true,
  "launchUrl": "swagger",
  "applicationUrl": "http://localhost:4000;",
  "environmentVariables": {
    "ASPNETCORE_ENVIRONMENT": "Development"
  }
}

Enter fullscreen mode Exit fullscreen mode

That is all the setup that is needed. Your WebApi is now configured and ready to run! Go to the terminal and run dotnet run. If it's successful, there should be a message saying that it's listening on the url that was specified earlier.

Creating A Controller With An Endpoint

Now, it's time to make the WebApi function by adding an endpoint. First we will need to create a Controllers folder in the root of the project. Inside the Controllers folder, create a new file named UserController.cs. In the UserController.cs file paste this code as the template:

// userController.cs

using Microsoft.AspNetCore.Mvc;
using System.Text.Encodings.Web
namespace test.API.Controllers
{
[ApiController]
[Route("api/users")]
    public class HelloWorldController : ControllerBase

        [HTTPGet("test")]
        public string Test()
        {
            return "This is a test endpoint";

    }
}
Enter fullscreen mode Exit fullscreen mode

Stop and restart the server, then go to the browser and type in the serverUrl with 'api/users/test' appended to the end. It should return the message from in the test method that was just created.

Creating A Model

A model is a structure that will show the shape of data that will be returned by an endpoint. First, create a folder in the root of the project named 'Models'. All models will live here. Inside that folder create a file called User.cs. Inside the User.cs file, add the following code:

// User.cs

using System;
namespace daily_debrief.API
{
    public class User
    {
        public DateTime created { get; set; 
        public string FirstName { get; set; 
        public string LastName { get; set; 
        public string EmailAddress { get; set; 
        public string Username { get; set; }
    }
}
Enter fullscreen mode Exit fullscreen mode

Then go to the UserController.cs file and add using test.API.Models; to the top of the file and the following code below the existing endpoint:

UserController.cs

HttpGet("testUser/{email}")]
public IActionResult GetUser(string email)
{

    User testUser = new User()
    {
        created = DateTime.Now,
        FirstName = "Blake",
        LastName = "Lamb",
        EmailAddress = email,
        Username = "blamb31"
    };

    return Ok(testUser);
}
Enter fullscreen mode Exit fullscreen mode

After stopping and restarting the server again, you can now call the endpoint '/api/users/test/blake@blakelamb.com' and see the return of a User object with that email.

Recap

C#/.NET can be a good language to use as the backend of an app. With some templates that already come with C#/.NET it's pretty simple to get a server up and running. Adding controllers, endpoints and models is also simple and allows data to be passed back to the user easily.

Top comments (4)

Collapse
 
webjose profile image
José Pablo Ramírez Vargas

.Net produces probably the most scalable of backends, being capable of transacting 10x more than NodeJS. Having said that, one has to be careful with the simple template that is produced when creating an ASP.Net project because it is super simple and unrealistic. For example, you should always use Task<IActionResult> as return types for your controller methods. You should also avoid using Model Validation built-in since it is not SOLID-compliant (the ModelState.IsValid thing you'll see a lot).

In general, ASP.Net is amazing, just beware of the bad practices.

Collapse
 
fullstackcodr profile image
fullstackcodr

I agree with the above statements. Especially with the Task<IActiomResult> point, the code should be as much async possible.

I usually go with FluentValidation instead of the obsolete Model Validation. What would be another alternative for this?

Collapse
 
webjose profile image
José Pablo Ramírez Vargas • Edited

Since data validation is something that should be carried along with your business logic, I'd say it cannot be tied to any transport framework, such as HTTP. This supports good layering practices where one layer does not have to know the nature of other layers.

Having said that, FluentValidation, as long as it is not ASP.net-dependant, is probably as good choice as any other framework/protocol-independent validation library. Personally, I simply code implementations of a generic interface:

public enum ErrorTypes
{
    Unknown = 0,
    Validation = 1,
    Security = 2,
    Execution = 3
} // Add anything you need.  These are my usual 3.

public class Error
{
    // Shape error in a way that is informative, serializable, yet neutral in regards to transport.
    // One must not create classes in the business layers that are HTTP-aware (or transport protocol-aware).
    public int Code { get; set; }
    public string Message { get; set; }
    public ErrorTypes Type { get; set; }
}

public class ValidationResult
{
    public bool IsValid { get; }
    public List<Error> Errors { get; } = new();

    public ValidationResult(bool isValid = true)
    {
        IsValid = isValid;
    }

    public ValidationResult(IEnumerable<Error> errors)
    {
        Errors.AddRange(errors);
        IsValid = Errors.Count == 0;
    }
}

public interface IValidator<TData>
{
    // Where context can be used to pass additional data.  Useful for generic validators.
    Task<ValidationResult> ValidateAsync(TData data, object context = null);
}
Enter fullscreen mode Exit fullscreen mode

Then I just create data validators that implement the interface and inject them through the IoC container.

Thread Thread
 
fullstackcodr profile image
fullstackcodr

I like that indeed, I do use something similar (tailor-made) but when my validation rules have to be more complicated. Thanks for sharing!