Symfony 7 vs. .NET Core 8 - Web application; the basics
Tags: symfony, dotnetcore, php, csharp
Published: 2024-05-06 08:00:35

## Disclaimer

This is a tutorial or a training course. Please don't expect a walk-through tutorial showing how to use ASP.NET Core. It only compares similarities and differences between Symfony and ASP.NET Core.

## The Web server

When developing any PHP application, we will need a web server to serve static files and forward requests to `php-fpm`. PHP has a built-in web server that can be used for development. We can use this one or the one provided by Symfony. In both cases, the provided web servers are for development purposes only. We won't be using them when deploying our application to production. There, we will still need to set up something like nginx or Apache.

This is different from how ASP.NET Core 8 will handle requests. It comes with a bundled web server called [Kestrel](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/servers/kestrel?view=aspnetcore-8.0). We can still use IIS if we prefer (only on Windows, obviously); but the default is Kestrel. Since it is production-ready, we don't need anything else.

## Creating a project

With Symfony's CLI, we can bootstrap three types of applications:
* a skeleton application (almost an empty project)
* a web application
* an API application

We want to start with a web application, so we can create a new project like this:

```bash
symfony new --webapp SymfonyWebApplication
```

The above will bootstrap a Symfony application with many packages and features.

This is very similar to .NET. We can bootstrap a project from a template. There are built-in templates, but we can always create our own.

To see what options we have for a web application, let's list all the templates with `web`:

```bash
dotnet new list web
These templates matched your input: 'web'

Template Name                                 Short Name    Language  Tags                      
--------------------------------------------  ------------  --------  --------------------------
ASP.NET Core Empty                            web           [C#],F#   Web/Empty                 
ASP.NET Core Web API                          webapi        [C#],F#   Web/Web API/API/Service   
ASP.NET Core Web API (native AOT)             webapiaot     [C#]      Web/Web API/API/Service   
ASP.NET Core Web App (Model-View-Controller)  mvc           [C#],F#   Web/MVC                   
ASP.NET Core Web App (Razor Pages)            webapp,razor  [C#]      Web/MVC/Razor Pages       
Blazor Web App                                blazor        [C#]      Web/Blazor/WebAssembly    
Blazor WebAssembly Standalone App             blazorwasm    [C#]      Web/Blazor/WebAssembly/PWA
Web Config                                    webconfig               Config
```

We will choose `mvc` as it is the closest to Symfony's approach and bootstraps an MVC-like application.

```bash
dotnet new mvc
```

## Application's entry point

Both Symfony and .NET Core have an entry point.

Symfony's version is pretty simplistic:

```php
// public/index.php
<?php

use App\Kernel;

require_once dirname(__DIR__).'/vendor/autoload_runtime.php';

return function (array $context) {
    return new Kernel($context['APP_ENV'], (bool) $context['APP_DEBUG']);
};
```

A lot of magic happens behind the scenes or is delegated to configuration files.

On the other hand, .NET puts everything into the code. The entry point looks like this:

```c#
// Program.cs
var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddControllersWithViews();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Home/Error");
    // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthorization();

app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");

app.Run();
```

## A simple page

A bootstrapped application will render a default page. But let's try to add another one. We can follow Symfony's example with a page showing a randomly generated number. This is how we can do it with both frameworks.

### Symfony

```php
<?php
// src/Controller/LuckyController.php
namespace App\Controller;

use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;

class LuckyController
{
    #[Route('/lucky/number')]
    public function number(): Response
    {
        $number = random_int(0, 100);

        return new Response(
            '<html><body>Lucky number: '.$number.'</body></html>'
        );
    }
}
```

### .NET Core

```c#
// Controllers/LuckyNumberController.cs
using Microsoft.AspNetCore.Mvc;

namespace App.Controllers;

public class LuckyNumberController
{
    [Route("/lucky/number")]
    public string Number()
    {
        int randomNumber = new Random().Next(100);

        return $"Lucky number: {randomNumber}";
    }
}
```

## First impression

### It feels similar

You can bootstrap a web application (MVC-like) to create the necessary scaffolding.

### Web server

With Symfony, we need an external web server to take the application to production. A .NET Core app comes with the Kestrel web server and is ready to be deployed.

### Configuration

Symfony configuration happens in external files, while .NET puts everything into code (which makes sense because it is a compiled language). We will get into more details later.

### Controllers

The actual controller looks astonishingly similar. The only differences are the syntax and the fact that in Symfony, we need to return a Response object, and in .NET, we can return a string (that will be wrapped into the correct HTML tags).

### Folder structures and namespaces

While not strictly necessary, C# usually follows a namespacing/folder structure identical to PHP's PSR-4 standard. This definitely simplifies navigating through the code.

## What's next?

We didn't explore routing and rendering/templating in-depth, so those two topics will come next.
Feel free to leave a comment or reach out!