# 19. Web, desktop and games

> Chapter 19: build a web API with ASP.NET Core, a desktop window with Avalonia, and games with MonoGame and raylib, and find the samples to study.

Canonical: https://alice-lang.org/documentation/learn/applications/

[Documentation index](https://alice-lang.org/documentation/llms.txt) · [Complete book](https://alice-lang.org/llms-full.txt)

Alice does not come with its own web framework, GUI toolkit or game engine. It does not need one: .NET has mature ones, and Alice uses them directly. This short chapter shows the entry point for each kind of application and points at complete samples. The ideas are the ones from [chapter 14](https://alice-lang.org/documentation/learn/dotnet.md): .NET types by name, lambdas where .NET expects delegates, and inheriting .NET classes.

## 19.1 A web API with ASP.NET Core

ASP.NET Core is .NET's web framework. An Alice project uses it through a **framework reference**. Create a project and add a file `Directory.Build.props` next to `alice.toml`:

```sh
alice new hello-api
cd hello-api
```

```xml
<Project>
  <ItemGroup>
    <FrameworkReference Include="Microsoft.AspNetCore.App" />
  </ItemGroup>
</Project>
```

Then write the service in `src/main.al`:

```alice web-project="src/main.al" skip="a web server: built, started and requested by npm run test:projects"
using Microsoft.AspNetCore.Builder
using Microsoft.AspNetCore.Http

record Health(status : String)
module Routes
  def self.health : IResult
    Results.Ok(Health.new("ok"))
  end
end

builder = WebApplication.CreateBuilder(ARGV)
app = builder.Build()
app.MapGet("/health", -> { Routes.health })
app.Run()
```

Run it with `alice run` and request it:

```sh
curl http://localhost:5000/health
```

```text
{"status":"ok"}
```

The record gives the JSON its shape. `Routes.health` returns an `IResult`, so ASP.NET knows the response type. The book's test suite builds this project, starts the server and requests `/health`.

From here, everything in ASP.NET's documentation applies: routing, middleware, dependency injection, authentication. The [web guide](https://alice-lang.org/documentation/guides/web.md) has the details, and [`examples/web/aspnet`](https://github.com/alicelanguage/alice/tree/main/examples/web/aspnet) a larger service.

## 19.2 A desktop window with Avalonia

[Avalonia](https://avaloniaui.net) is a cross-platform UI toolkit for Windows, macOS and Linux. The layout is written in XAML; the code-behind is an Alice class that inherits from `Window`:

```alice skip="needs the Avalonia NuGet packages and its XAML file"
using Avalonia
using Avalonia.Controls
using Avalonia.Markup.Xaml

namespace Ava
  class MainWindow < Window
    @clicks : Int32 = 0

    def initialize
      AvaloniaXamlLoader.Load(self)
    end

    def bump
      @clicks += 1
      greeting.Text = "clicked #{@clicks}"
    end

    def greeting : TextBlock
      FindControl<TextBlock>("Greeting").not_nil!
    end
  end
end
```

`FindControl<TextBlock>("Greeting")` finds the control declared in the XAML file; it may not exist, so its result is nilable and `not_nil!` asserts that it does. The complete program, including the XAML and a headless test run, is [`examples/ui/avalonia`](https://github.com/alicelanguage/alice/tree/main/examples/ui/avalonia).

## 19.3 Games with MonoGame and raylib

`alice new --game` creates a project with MonoGame, a framework used by many commercial games:

```sh
alice new rabbit-game --game
cd rabbit-game
alice run
```

A game is a class that inherits MonoGame's `Game` and overrides its lifecycle methods:

```alice skip="needs the MonoGame package and a graphics device"
using Microsoft.Xna.Framework
using Microsoft.Xna.Framework.Graphics

class HelloGame < Game
  def initialize
    GraphicsDeviceManager.new(self)
    self.Window.Title = "Hello, Wonderland"
  end

  def Draw(time : GameTime)
    GraphicsDevice.Clear(Color.CornflowerBlue)
    super
  end
end

HelloGame.new.Run
```

`Draw` keeps its .NET name because it overrides a .NET method. `super` calls MonoGame's own `Draw`.

Keep the game's rules, such as movement, collisions and scoring, in plain Alice classes and methods with no graphics. Then `alice test` can check them without opening a window, and the [proofs of chapter 13](https://alice-lang.org/documentation/learn/proofs.md) can cover them.

The samples to study:

| Sample                                                                            | Shows                                      |
| --------------------------------------------------------------------------------- | ------------------------------------------ |
| [BounceGame](https://github.com/alicelanguage/alice/tree/main/samples/BounceGame) | the smallest MonoGame program              |
| [Breakout](https://github.com/alicelanguage/alice/tree/main/samples/Breakout)     | a complete game with logic tested headless |
| [celeste](https://github.com/alicelanguage/alice/tree/main/samples/celeste)       | a larger platformer on raylib              |
| [wonderland](https://github.com/alicelanguage/alice/tree/main/samples/wonderland) | a text adventure with a Ruby-style DSL     |

## 19.4 Data and databases

Entity Framework Core works from Alice: a `DbContext` subclass with `DbSet` properties, queried with LINQ, which EF translates to SQL. See [`examples/data/efcore`](https://github.com/alicelanguage/alice/tree/main/examples/data/efcore).

:::caution\[Common mistakes]

- **Missing the ASP.NET framework reference.** Without `Directory.Build.props`, `Microsoft.AspNetCore.*` types are unknown (`AL0307`).
- **Running a web server in the playground.** The browser playground cannot listen on a port. Run web projects locally.
- **Renaming overridden .NET methods.** An override of `Draw` must be called `Draw`, not `draw`.
- **Game logic inside `Draw`.** Rendering code cannot be tested without a window. Keep rules in plain methods.
  :::

## Exercises

1. Add a second route `/menu` to the web API that returns a record with a list of tea names.
2. Why does `FindControl<TextBlock>("Greeting")` return a nilable value, and what does `not_nil!` do if the control is missing?
3. Which parts of a game would you put under `alice test`, and which can only be checked by playing?

<details>
<summary>Answers</summary>

1. Add a record and a route next to the health check:

   ```alice skip="a web server"
   record Menu(teas : Array(String))

   app.MapGet("/menu", -> { Results.Ok(Menu.new(["Assam", "Sencha"])) })
   ```

   A request then returns `{"teas":["Assam","Sencha"]}`.

2. The XAML may not contain a control with that name, so the .NET method returns `null` in that case. `not_nil!` raises an exception if the value is `nil`, so a misspelled name fails loudly at that line instead of later.

3. Rules, movement, collision, scoring and level logic can be tested, and their invariants proven. Rendering, input feel, audio and frame pacing need a person playing the game.

</details>

## Summary

- Alice builds applications on .NET's frameworks: ASP.NET Core for the web, Avalonia for desktop, MonoGame and raylib for games, EF Core for databases.
- ASP.NET needs a `FrameworkReference` in `Directory.Build.props`; NuGet frameworks are added with `alice add`.
- Alice classes inherit framework classes and override their methods under the .NET names.
- Keep logic separate from presentation so that it can be tested and proven.

[Chapter 20](https://alice-lang.org/documentation/learn/webassembly.md) runs Alice in the browser.

## Continue reading

- Previous: [18. Projects and packaging](https://alice-lang.org/documentation/learn/packaging.md)
- Next: [20. WebAssembly](https://alice-lang.org/documentation/learn/webassembly.md)
