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
-
Input (Client): The user sends a name using
?name=Sabin. - Controller: Receives the name and asks the service to create a card.
-
Service: Fills out a predefined contract called
HelloResponse. - 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.
- Right-click the project (
HelloFlow) → Add → New Folder - Name the folder
Models - Right-click
Models→ Add → Class - 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; }
}
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;
}
}
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);
}
Notice that the controller:
- Does not create the response
- Does not modify the data
- Simply forwards input and output
🚀 4️⃣ Run and Test
- Click the Run button
- Open Swagger and select
/api/Hello - Enter a value for
name(e.g.Sabin) - 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"
}
🧠 Why This Matters
In Python, it is common to return loose dictionaries like:
{"msg": "hello", "loc": "here"}
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)