DEV Community

Sabin Sim
Sabin Sim

Posted on

C#.NET - day 02

Introducing a Contract

From simple strings to structured data in ASP.NET Core

Introduction

Compared to my Python-related posts, this series clearly attracts less attention. Still, I believe there may be someone who needs this way of learning.

In any case, I plan to continue studying C#. This is not only for others, but also for my future self—to leave a clear trace of how I studied and what I focused on at this point in time.

At the same time, writing these posts helps me create an environment where I can revisit and reinforce what I have already learned.


Why Step 1.0?

Until now, we only exchanged very simple data—just a short string like “Hello”.

From this step onward, we stop passing loose strings and start exchanging data based on a defined structure (a class).

This is one of the biggest differences between C# and Python, and also a key reason why C# systems tend to be more robust as they grow.

Our new goal is simple:

“Receive a name and return a properly structured business card.”


🌊 Flow: System Overview

  1. Input (Client): The user sends a name using ?name=Sabin.
  2. Controller: Receives the name and asks the service to create a card.
  3. Service: Fills out a predefined contract called HelloResponse.
  4. Output: The client receives clean, structured JSON.

1️⃣ Step 1: Creating the Contract (Model)

First, we create an empty container—a contract that defines what kind of data we exchange.

  1. Right-click the project (HelloFlow) → Add → New Folder
  2. Name the folder Models
  3. Right-click ModelsAdd → Class
  4. Name it HelloResponse

Code:

namespace HelloFlow.Models;

public class HelloResponse
{
    public string Message { get; set; }
    public DateTime CreatedAt { get; set; }
    public string Location { get; set; }
}
Enter fullscreen mode Exit fullscreen mode

This class acts as a clear agreement:

  • What fields exist
  • What types they must have
  • What shape the response will always follow

2️⃣ Step 2: Upgrading the Kitchen (Service)

Next, we update the service so it no longer returns a simple string. Instead, it fills and returns the contract we just created.

Open Services/HelloService.cs and replace its contents.

Code:

using HelloFlow.Models;

namespace HelloFlow.Services;

public class HelloService
{
    public HelloResponse GetHello(string name)
    {
        var response = new HelloResponse
        {
            Message = $"Hello, {name}! Welcome to C#.",
            CreatedAt = DateTime.Now,
            Location = "Cazis, Switzerland"
        };

        return response;
    }
}
Enter fullscreen mode Exit fullscreen mode

The service now has a clear responsibility:

  • Receive input data
  • Create a structured response
  • Return the completed contract

3️⃣ Step 3: Upgrading the Counter (Controller)

The controller also needs to change. It must now accept a name and return the structured result without modification.

Open Controllers/HelloController.cs and update only the SayHello method.

Code:

[HttpGet]
public IActionResult SayHello(string name)
{
    var result = _service.GetHello(name);
    return Ok(result);
}
Enter fullscreen mode Exit fullscreen mode

Notice that the controller:

  • Does not create the response
  • Does not modify the data
  • Simply forwards input and output

🚀 4️⃣ Run and Test

  1. Click the Run button
  2. Open Swagger and select /api/Hello
  3. Enter a value for name (e.g. Sabin)
  4. Click Execute

If everything works, you should see a structured response like this:

{
  "message": "Hello, Sabin! Welcome to C#.",
  "createdAt": "2026-01-03T17:50:00.123456",
  "location": "Cazis, Switzerland"
}
Enter fullscreen mode Exit fullscreen mode

🧠 Why This Matters

In Python, it is common to return loose dictionaries like:

{"msg": "hello", "loc": "here"}
Enter fullscreen mode Exit fullscreen mode

This is flexible, but also fragile. If one field name changes, you may have to search and update many places manually.

By defining a contract like HelloResponse in C#, the compiler helps you. If the contract changes, every dependent place shows an error immediately.

This is not about convenience—it is about building systems that stay reliable as they grow.


✍️ My Notes & Reflections

  • Previously, I thought of the controller as a simple conveyor belt. In this step, however, it felt more like a staff member interacting with the customer.
  • My intuitive impression was that the controller is asking the customer for required information. It feels like saying, “For this order, you need to write your name so the service can create the response in this format.”
  • In that sense, the controller receives the name from the client and passes it to the service, while the service focuses on creating the actual result.

Top comments (0)