๐ .NET์ ๊ฐ๋ ฅํ FBA(File-Based Application) ๊ธฐ๋ฅ์ ํ์ฉํ ์ค์ ์์ ๋ชจ์
C# File-Based Application (FBA) ๊ธฐ๋ฅ์ ํ์ฉํ ๋ค์ํ ์์ ์ฝ๋ ๋ชจ์์ ๋๋ค. .NET 10 ์ด์์ FBA ๊ธฐ๋ฅ์ ์ฌ์ฉํ์ฌ ๋จ์ผ ํ์ผ๋ก ์์ฑ๋ ์คํ ๊ฐ๋ฅํ C# ์คํฌ๋ฆฝํธ ์์ ๋ค์ ์ ๊ณตํฉ๋๋ค.
๋ฐํ ์๋ฃ ๊ฐ์ด๋ณด๊ธฐ: https://1drv.ms/p/c/318484c5aad6b73d/EQNehpg4jN5CmVcTh-qDoecBGqBe3gMwuGh3bbHf7EW4yQ?e=M1RstJ
File-Based Application(FBA)์ .NET์ ํ์ ์ ์ธ ๊ธฐ๋ฅ์ผ๋ก, ๋จ์ผ C# ํ์ผ์ ํ๋ก์ ํธ ํ์ผ(.csproj) ์์ด ์ง์ ์คํํ ์ ์๊ฒ ํด์ค๋๋ค. ์ด๋ ๋ค์๊ณผ ๊ฐ์ ์ฅ์ ์ ์ ๊ณตํฉ๋๋ค:
- โจ ๊ฐํธํ ์์: ํ๋ก์ ํธ ๊ตฌ์กฐ ์์ด ๋จ์ผ ํ์ผ๋ก ์ ํ๋ฆฌ์ผ์ด์ ์์ฑ
- ๐ง ๋น ๋ฅธ ํ๋กํ ํ์ดํ: ์์ด๋์ด๋ฅผ ๋น ๋ฅด๊ฒ ํ ์คํธํ๊ณ ๊ฒ์ฆ
- ๐ฆ ์์กด์ฑ ๊ด๋ฆฌ:
#:package๋๋ ํฐ๋ธ๋ก NuGet ํจํค์ง ์ง์ ์ฐธ์กฐ - ๐ญ SDK ์ ํ:
#:sdk๋๋ ํฐ๋ธ๋ก ํ์ํ SDK ์ง์ - โ๏ธ ๋น๋ ์์ฑ:
#:property๋๋ ํฐ๋ธ๋ก MSBuild ์์ฑ ์ค์ - ๐ ์คํฌ๋ฆฝํธ ์คํ: Shebang(
#!/usr/bin/env dotnet)์ ํตํ ์คํฌ๋ฆฝํธ ์คํ
- FBA๋ ๋ฌด์์ธ๊ฐ์?
- ์๊ตฌ์ฌํญ
- ๋น ๋ฅธ ์์
- ์์ ์ค๋ช
- FBA ๋๋ ํฐ๋ธ ๊ฐ์ด๋
- ๋ฌธ์ ํด๊ฒฐ
- ๊ธฐ์ฌํ๊ธฐ
- ๋ผ์ด์ ์ค
- ์ฐธ๊ณ ์๋ฃ
- .NET 10.0 SDK ์ด์
- FBA ๊ธฐ๋ฅ์ ์์ ํ ์ง์ํ๋ ์ต์ ๋ฒ์ ์ฌ์ฉ ๊ถ์ฅ
- ์ค์น ํ์ธ:
dotnet --version
- ์ด์์ฒด์ : macOS, Linux, ๋๋ Windows
- ๋ชจ๋ ์์ ๋ ํฌ๋ก์ค ํ๋ซํผ์ผ๋ก ์ค๊ณ๋จ
- Python 3.x (05-native-aot.py ์คํ ์)
- Native AOT ๋ผ์ด๋ธ๋ฌ๋ฆฌ ํธ์ถ ์์ ์ ํ์
- Java 17+ ๋ฐ wget (05-native-aot.java ์คํ ์)
- Java์์ Native AOT ๋ผ์ด๋ธ๋ฌ๋ฆฌ ํธ์ถ ์์ ์ ํ์
- JNA(Java Native Access) ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์๋ ๋ค์ด๋ก๋
- Node.js 18+ ๋ฐ npm (05-native-aot.js ์คํ ์)
- Node.js์์ Native AOT ๋ผ์ด๋ธ๋ฌ๋ฆฌ ํธ์ถ ์์ ์ ํ์
- koffi ํจํค์ง ์๋ ์ค์น
- GCC/Clang (05-staticlib-c.c ์ปดํ์ผ ์)
- C ์ปดํ์ผ๋ฌ ๋ฐ iconv ๋ผ์ด๋ธ๋ฌ๋ฆฌ
- macOS: Xcode Command Line Tools (
xcode-select --install) - Linux:
build-essentialํจํค์ง
- OpenRouter API ํค (06-agui-server.cs ์คํ ์)
- AI ์์ด์ ํธ ์์ ์ ํ์
- OpenRouter์์ ๋ฌด๋ฃ ๊ณ์ ์์ฑ ๊ฐ๋ฅ
- Visual Studio Code + C# Dev Kit ํ์ฅ
- JetBrains Rider
- Visual Studio 2022 (Windows)
- LINQPad 8 (์ด ์ ์ฅ์์ ์๋ ์คํ ํ๊ฒฝ)
# ์ ์ฅ์ ํด๋ก
git clone <repository-url>
cd csharp-fba-zero-to-hero
# ๊ฐ์ฅ ๊ฐ๋จํ ์์ ์คํ
chmod +x 01-shell-standard.cs
./01-shell-standard.cs
# ์น API ์์ ์คํ
chmod +x 02-random-webapi.cs
./02-random-webapi.cs
# ๋ค๋ฅธ ํฐ๋ฏธ๋์์: curl http://localhost:5000/๊ฐ ์์ ๋ FBA์ ํน์ ๊ธฐ๋ฅ๊ณผ ์ค์ ์ฌ์ฉ ์ฌ๋ก๋ฅผ ๋ณด์ฌ์ค๋๋ค. ๋์ด๋ ์์ผ๋ก ์ ๋ ฌ๋์ด ์์ผ๋ฉฐ, ๊ธฐ์ด๋ถํฐ ๊ณ ๊ธ ์ฃผ์ ๊น์ง ๋ค๋ฃน๋๋ค.
๐ ํ์ต ๋ชฉํ: FBA์ ๊ธฐ๋ณธ Shebang ์ฌ์ฉ๋ฒ๊ณผ ์คํฌ๋ฆฝํธ ์คํ ๋ฐฉ์ ์ดํด
๊ฐ๋จํ "Hello World" ์คํ์ผ์ ์ ์คํฌ๋ฆฝํธ ์์ ์ ๋๋ค. C# ํ์ผ์ Unix/Linux ์คํ์ผ์ ์คํ ๊ฐ๋ฅํ ์คํฌ๋ฆฝํธ๋ก ๋ง๋๋ ๋ฐฉ๋ฒ์ ๋ณด์ฌ์ค๋๋ค.
ํต์ฌ ๊ฐ๋ :
- Shebang(
#!)์ ์ฌ์ฉํ ์ธํฐํ๋ฆฌํฐ ์ง์ - ์คํ ๊ถํ ๋ถ์ฌ (
chmod +x) - ์ง์ ์คํ ๊ฐ๋ฅํ C# ํ์ผ
ํ์ค shebang ๋ฐฉ์์ ์ฌ์ฉํ ๊ธฐ๋ณธ ์คํฌ๋ฆฝํธ์ ๋๋ค.
์คํ ๋ฐฉ๋ฒ:
# ์คํ ๊ถํ ๋ถ์ฌ
chmod +x 01-shell-standard.cs
# ์คํ
./01-shell-standard.cs์ถ๋ ฅ:
No lemon, no melon.
๋์ฒด shebang ๋ฐฉ์์ ์ฌ์ฉํ ์คํฌ๋ฆฝํธ์ ๋๋ค. ์ด ๋ฐฉ์์ JBang์์ ์ฌ์ฉํ๋ ๋ฐฉ์๊ณผ ๊ฐ์ ๋ฐฉ์์ ๋๋ค.
์คํ ๋ฐฉ๋ฒ:
# ์คํ ๊ถํ ๋ถ์ฌ
chmod +x 01-shell-alt.cs
# ์คํ
./01-shell-alt.cs์ถ๋ ฅ:
No lemon, No melon.
๐ ํ์ต ๋ชฉํ: FBA์์ ASP.NET Core ์น ์ ํ๋ฆฌ์ผ์ด์ ์์ฑ ๋ฐฉ๋ฒ, SDK ์ง์ ๋ฐ ์์กด์ฑ ์ฃผ์ ์ดํด
ASP.NET Core๋ฅผ ์ฌ์ฉํ ๊ฐ๋จํ ์น API ์๋ฒ์ ๋๋ค. ๋๋ค ์ซ์๋ฅผ ๋ฐํํ๋ ์๋ํฌ์ธํธ๋ฅผ ์ ๊ณตํฉ๋๋ค.
ํต์ฌ ๊ฐ๋ :
#:sdk Microsoft.NET.Sdk.Web- Web SDK ์ฌ์ฉ#:property PublishAot=false- AOT ์ปดํ์ผ ๋นํ์ฑํ- Minimal API ํจํด
- Dependency Injection (DI)
- Singleton ์๋น์ค ๋ฑ๋ก (
Random.Shared)
์คํ ๋ฐฉ๋ฒ:
# ์คํ ๊ถํ ๋ถ์ฌ
chmod +x 02-random-webapi.cs
# ์คํ
./02-random-webapi.csํ ์คํธ:
# ๋ค๋ฅธ ํฐ๋ฏธ๋์์ ์คํ
curl http://localhost:5000/์๋ต ์์:
{
"ts": "2025-11-26T12:34:56.7890123Z",
"val": 7
}๐ ํ์ต ๋ชฉํ: .NET Aspire๋ฅผ ์ฌ์ฉํ ๋ถ์ฐ ์ ํ๋ฆฌ์ผ์ด์ ๊ตฌ์ถ, ์๋น์ค ๊ฐ ํต์ ๋ฐ ์ค์ผ์คํธ๋ ์ด์
.NET Aspire๋ฅผ ์ฌ์ฉํ ๋ถ์ฐ ์ ํ๋ฆฌ์ผ์ด์ ์ค์ผ์คํธ๋ ์ด์ ์์ ์ ๋๋ค. Garnet(Redis ํธํ) ์บ์ ์๋ฒ, Worker ์๋น์ค, Minimal API๋ฅผ ํจ๊ป ์คํํฉ๋๋ค.
ํต์ฌ ๊ฐ๋ :
#:sdk Aspire.AppHost.Sdk- Aspire AppHost SDK ์ฌ์ฉ#:package๋๋ ํฐ๋ธ๋ก NuGet ํจํค์ง ์ฐธ์กฐ- ์๋น์ค ๋์ค์ปค๋ฒ๋ฆฌ ๋ฐ ์ฐธ์กฐ ๊ด๋ฆฌ
WaitForํจํด์ผ๋ก ์๋น์ค ์์ ์์ ์ ์ด- User Secrets๋ฅผ ํตํ ๋น๋ฐ ์ ๋ณด ๊ด๋ฆฌ
- Aspire Dashboard๋ฅผ ํตํ ๋ถ์ฐ ์ถ์ ๋ฐ ๋ชจ๋ํฐ๋ง
03-apphost.cs: ์ฑ ํธ์คํธ - ์ ์ฒด ์ ํ๋ฆฌ์ผ์ด์ ์ค์ผ์คํธ๋ ์ดํฐ03-minapi.cs: Minimal API - Redis์์ ๋ฉ์์ง๋ฅผ ์ฝ์ด ๋ฐํํ๋ ์น API03-worker.cs: Background Worker - 1์ด๋ง๋ค Redis์ ํ์ฌ ์๊ฐ์ ์ ๋ฐ์ดํธ03-apphost.json: ์ฑ ํธ์คํธ ์ค์ ํ์ผ
์คํ ๋ฐฉ๋ฒ:
# ์คํ ๊ถํ ๋ถ์ฌ
chmod +x 03-apphost.cs
# ์คํ
./03-apphost.csํน์ง:
- Aspire Dashboard๊ฐ ์๋์ผ๋ก ์คํ๋ฉ๋๋ค (
http://localhost:18888) - Garnet (Redis ํธํ) ์บ์ ์๋ฒ๊ฐ ์๋์ผ๋ก ์์๋ฉ๋๋ค
- Worker๊ฐ 1์ด๋ง๋ค LastUpdated ํค๋ฅผ ์ ๋ฐ์ดํธํฉ๋๋ค
- Minimal API๊ฐ ๋ฉ์์ง์ ๋ง์ง๋ง ์ ๋ฐ์ดํธ ์๊ฐ์ ๋ฐํํฉ๋๋ค
ํ ์คํธ:
# Aspire Dashboard์์ minapi์ ํฌํธ ํ์ธ ํ
curl http://localhost:<minapi-port>/์ํคํ ์ฒ ํ๋ฆ:
โโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโ
โ Worker โโโโโโ>โ Garnet โ<โโโโโโ MinAPI โ
โ (03-worker) โ writeโ (Redis) โ read โ (03-minapi) โ
โโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโ
โ โ
๋งค 1์ด๋ง๋ค HTTP ์์ฒญ ์
LastUpdated ์
๋ฐ์ดํธ ๋ฉ์์ง ์กฐํ ๋ฐ ๋ฐํ
๐ ํ์ต ๋ชฉํ: FBA์์ ํฌ๋ก์ค ํ๋ซํผ GUI ์ ํ๋ฆฌ์ผ์ด์ ์์ฑ, MVVM ํจํด ์ ์ฉ
Avalonia UI๋ฅผ ์ฌ์ฉํ ํฌ๋ก์ค ํ๋ซํผ ๋ฐ์คํฌํฑ ๊ณ์ฐ๊ธฐ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋๋ค. WPF์ ์ ์ฌํ XAML ๊ธฐ๋ฐ UI๋ฅผ ์ฝ๋๋ก ๊ตฌํํ ์์ ์ ๋๋ค.
ํต์ฌ ๊ฐ๋ :
#:property OutputType=WinExe- Windows ์คํ ํ์ผ๋ก ๋น๋- Avalonia UI ํ๋ ์์ํฌ
- MVVM (Model-View-ViewModel) ํจํด
- CommunityToolkit.Mvvm์ ํ์ฉํ ๊ด์ฐฐ ๊ฐ๋ฅ ์์ฑ
- RelayCommand๋ฅผ ํตํ ์ปค๋งจ๋ ํจํด
- Dependency Injection๊ณผ ์๋น์ค ์๋ช ์ฃผ๊ธฐ
- ์ฝ๋ ๊ธฐ๋ฐ UI ๊ตฌ์ฑ (Code-behind UI)
์คํ ๋ฐฉ๋ฒ:
# ์คํ ๊ถํ ๋ถ์ฌ
chmod +x 04-avalonia.cs
# ์คํ
./04-avalonia.csํน์ง:
- CommunityToolkit.Mvvm์ ์ฌ์ฉํ MVVM ํจํด ๊ตฌํ
- ๊ธฐ๋ณธ ์ฌ์น์ฐ์ฐ ๊ธฐ๋ฅ (+, -, ร, รท)
- ํฌ๋ก์ค ํ๋ซํผ ์ง์ (Windows, macOS, Linux)
- Dependency Injection์ ํ์ฉํ ์๋น์ค ๊ตฌ์กฐ
๐ ํ์ต ๋ชฉํ: Native AOT ์ปดํ์ผ์ ํตํ ๋ค์ดํฐ๋ธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์์ฑ, ๋ค๋ฅธ ์ธ์ด์์ ์ํธ์ด์ฉ์ฑ
Native AOT ์ปดํ์ผ์ ํตํด C# ์ฝ๋๋ฅผ ๋ค์ดํฐ๋ธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ก ๋ณํํ๊ณ ๋ค์ํ ์ธ์ด(Python, C)์์ ํธ์ถํ๋ ์์ ์ ๋๋ค. C#์ ์ฑ๋ฅ๊ณผ ๋ค๋ฅธ ์ธ์ด์ ์ ์ฐ์ฑ์ ๊ฒฐํฉํ๋ ๋ฐฉ๋ฒ์ ๋ณด์ฌ์ค๋๋ค.
ํต์ฌ ๊ฐ๋ :
#:property PublishAot=True- Native AOT ์ปดํ์ผ ํ์ฑํ#:property OutputType=Library- ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ก ๋น๋#:property NativeLib=Static- ์ ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์์ฑ#:property RuntimeIdentifier=osx-arm64- ํ๊ฒ ํ๋ซํผ ์ง์ UnmanagedCallersOnly์์ฑ - ๋ค์ดํฐ๋ธ ํจ์ ๋ ธ์ถ- P/Invoke ์ญ๋ฐฉํฅ (C#์์ ๋ค์ดํฐ๋ธ๋ก)
- ์ธ์ด ๊ฐ ์ํธ์ด์ฉ์ฑ (C# โ Python/C)
- ์ ๋์ฝ๋ ๋ฌธ์์ด ๋ง์ฌ๋ง
- iconv๋ฅผ ํตํ UTF-8 โ UTF-16 ๋ณํ
05-native-aot.cs: C# ๋ค์ดํฐ๋ธ ๋์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์์ค (.dylib)05-native-aot.py: Python์์ ๋์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ํธ์ถ ์์ 05-native-aot.java: Java์์ ๋์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ํธ์ถ ์์ (JNA ์ฌ์ฉ)05-native-aot.js: Node.js์์ ๋์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ํธ์ถ ์์ (koffi ์ฌ์ฉ)05-staticlib-aot.cs: C# ๋ค์ดํฐ๋ธ ์ ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์์ค (.a)05-staticlib-c.c: C์์ ๋์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ํธ์ถ ์์
๋น๋ ๋ฐฉ๋ฒ:
# C# ์ฝ๋๋ฅผ ๋ค์ดํฐ๋ธ ๋์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ก ์ปดํ์ผ
dotnet publish ./05-native-aot.csPython์์ ์ฌ์ฉ:
# ์คํ ๊ถํ ๋ถ์ฌ
chmod +x 05-native-aot.py
# ์คํ
./05-native-aot.pyC์์ ์ฌ์ฉ:
# ์ปดํ์ผ ๋ฐ ์คํ
gcc -o 05-staticlib-c 05-staticlib-c.c artifacts/05-native-aot/05-native-aot.dylib -Wl,-rpath,artifacts/05-native-aot -liconv
./05-staticlib-cJava์์ ์ฌ์ฉ:
# JNA ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋ค์ด๋ก๋ (์ต์ด 1ํ)
wget -nc https://repo1.maven.org/maven2/net/java/dev/jna/jna/5.14.0/jna-5.14.0.jar
# ์ปดํ์ผ
javac -cp jna-5.14.0.jar 05-native-aot.java
# ์คํ
java -cp .:jna-5.14.0.jar NativeAotExampleNode.js์์ ์ฌ์ฉ:
# koffi ํจํค์ง ์ค์น (์ต์ด 1ํ)
npm install koffi
# ์คํ ๊ถํ ๋ถ์ฌ
chmod +x 05-native-aot.js
# ์คํ
./05-native-aot.js
# ๋๋
node 05-native-aot.js์ถ๋ ฅ ์์:
Testing Native AOT library from Node.js
==========================================
2025. 11. 26. ์คํ 11:56:52 Hello from Node.js!
2025. 11. 26. ์คํ 11:56:52 Native AOT ํธ์ถ ํ
์คํธ
2025. 11. 26. ์คํ 11:56:52 ์๋
ํ์ธ์!
All calls completed.
๋น๋ ๋ฐฉ๋ฒ:
# C# ์ฝ๋๋ฅผ ๋ค์ดํฐ๋ธ ์ ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ก ์ปดํ์ผ
dotnet publish ./05-staticlib-aot.cs
โ ๏ธ ์ฐธ๊ณ : ์ ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ .NET ๋ฐํ์ ์ข ์์ฑ์ด ํฌํจ๋์ง ์์ ์ง์ ๋งํฌ ์ ์ค๋ฅ๊ฐ ๋ฐ์ํ ์ ์์ต๋๋ค. ๋์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ(.dylib) ์ฌ์ฉ์ ๊ถ์ฅํฉ๋๋ค.
ํน์ง:
- UnmanagedCallersOnly ์์ฑ์ ์ฌ์ฉํ ๋ค์ดํฐ๋ธ ํจ์ ๋ ธ์ถ
- Python ctypes, Java JNA, Node.js koffi, C์์ C# ๋ผ์ด๋ธ๋ฌ๋ฆฌ ํธ์ถ
- UTF-16 ์ ๋์ฝ๋ ๋ฌธ์์ด ์ ๋ฌ ์ง์ (ํ๊ธ ํฌํจ)
- iconv ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ํตํ ๊ฐ๋จํ ๋ฌธ์ ์ธ์ฝ๋ฉ ๋ณํ (C)
- Java JNA์ Node.js koffi๋ฅผ ํตํ ๊ฐํธํ ๋ค์ดํฐ๋ธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ ๊ทผ
- JIT ์ปดํ์ผ๋ฌ ์์ด ๋น ๋ฅธ ์์ ์๊ฐ
- ์์ ๋ฐฐํฌ ํฌ๊ธฐ (๋จ์ผ ๋ค์ดํฐ๋ธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ)
- .NET ๋ฐํ์ ๋ถํ์ (self-contained)
์ฌ์ฉ ์ฌ๋ก:
- Python/Java/Node.js/C ํ๋ก์ ํธ์ ๊ณ ์ฑ๋ฅ C# ๋ผ์ด๋ธ๋ฌ๋ฆฌ ํตํฉ
- ๋ ๊ฑฐ์ ์์คํ ๊ณผ์ ์ฐ๋
- ์ฃ์ง ๋๋ฐ์ด์ค์ฉ ๊ฒฝ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ
- ๊ฒ์ ์์ง ํ๋ฌ๊ทธ์ธ
- ์๋ฒ ๋๋ ์์คํ ์ฉ ๋ค์ดํฐ๋ธ ๋ชจ๋
- JVM ๊ธฐ๋ฐ ์ ํ๋ฆฌ์ผ์ด์ ์์ .NET ์ฝ๋ ํ์ฉ
- Node.js ๋ฐฑ์๋์์ ๊ณ ์ฑ๋ฅ .NET ๋ชจ๋ ํ์ฉ
๐ ํ์ต ๋ชฉํ: AI ์์ด์ ํธ ๊ตฌ์ถ, ์ปค์คํ ๋๊ตฌ ํตํฉ, ์คํธ๋ฆฌ๋ฐ ์๋ต ์ฒ๋ฆฌ
Microsoft Agents AI ํ๋ ์์ํฌ๋ฅผ ์ฌ์ฉํ AI ์์ด์ ํธ ์๋ฒ/ํด๋ผ์ด์ธํธ ์์ ์ ๋๋ค. OpenAI ํธํ API๋ฅผ ํตํด Grok ๋ชจ๋ธ์ ํ์ฉํ๋ฉฐ, ์ปค์คํ ๋๊ตฌ(Function Calling)๋ฅผ ์ง์ํฉ๋๋ค.
ํต์ฌ ๊ฐ๋ :
-
Microsoft.Agents.AI ํ๋ ์์ํฌ
-
AG-UI (Agent Gateway User Interface) ํ๋กํ ์ฝ
-
OpenAI ํธํ API ์ฌ์ฉ (OpenRouter๋ฅผ ํตํ Grok ์ ๊ทผ)
-
Function Calling / Tool Use ํจํด
-
AIFunctionFactory๋ฅผ ํตํ ํจ์ ๋ฑ๋ก
-
์คํธ๋ฆฌ๋ฐ ์๋ต ์ฒ๋ฆฌ
-
User Secrets๋ฅผ ํตํ API ํค ๊ด๋ฆฌ
-
IChatClient ์ธํฐํ์ด์ค ํ์ฉ
-
06-agui-server.cs: AG-UI ์๋ฒ - AI ์์ด์ ํธ ํธ์คํ -
06-agui-client.cs: AG-UI ํด๋ผ์ด์ธํธ - ์์ด์ ํธ์ ๋ํ
์๋ฒ ์ค์ :
# OpenRouter API ํค ์ค์
dotnet user-secrets --id 06-agui-server set openrouter-key "YOUR_API_KEY_HERE"์๋ฒ ์คํ:
# ์คํ ๊ถํ ๋ถ์ฌ
chmod +x 06-agui-server.cs
# ์คํ
./06-agui-server.csํด๋ผ์ด์ธํธ ์คํ:
# ์ ํฐ๋ฏธ๋์์
chmod +x 06-agui-client.cs
# ์คํ
./06-agui-client.csํน์ง:
- OpenAI ํธํ API๋ฅผ ํตํ Grok 4.1 ๋ชจ๋ธ ์ฌ์ฉ
- ์ปค์คํ ๋๊ตฌ(Tools) ์ง์ (๋ง์ , ๋บ์ )
- ์คํธ๋ฆฌ๋ฐ ์๋ต ์ง์
- ๋ํํ CLI ์ธํฐํ์ด์ค
์ฌ์ฉ ์์:
User (:q or quit to exit): 25 ๋ํ๊ธฐ 17์?
[Run Started - Thread: xxx, Run: yyy]
25 ๋ํ๊ธฐ 17์ 42์
๋๋ค.
[Run Finished - Thread: xxx]
User (:q or quit to exit): :q
FBA์์ ์ฌ์ฉ ๊ฐ๋ฅํ ์ฃผ์ ๋๋ ํฐ๋ธ๋ค์ ๋๋ค:
#:sdk Microsoft.NET.Sdk // ๊ธฐ๋ณธ ์ฝ์ ์ ํ๋ฆฌ์ผ์ด์
#:sdk Microsoft.NET.Sdk.Web // ์น ์ ํ๋ฆฌ์ผ์ด์
#:sdk Microsoft.NET.Sdk.Worker // Worker ์๋น์ค
#:sdk Aspire.AppHost.Sdk@13.0.0 // Aspire AppHost (๋ฒ์ ์ง์ )#:package Newtonsoft.Json // ์ต์ ๋ฒ์
#:package Newtonsoft.Json@13.0.3 // ํน์ ๋ฒ์
#:package Microsoft.Extensions.Hosting@10.* // ์์ผ๋์นด๋ ๋ฒ์ #:property OutputType=Library // ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ก ๋น๋
#:property OutputType=WinExe // Windows ์คํ ํ์ผ
#:property PublishAot=true // Native AOT ํ์ฑํ
#:property PublishAot=false // Native AOT ๋นํ์ฑํ
#:property RuntimeIdentifier=osx-arm64 // ํ๊ฒ ํ๋ซํผ ์ง์
#:property TargetFramework=net10.0 // ํ๊ฒ ํ๋ ์์ํฌ#!/usr/bin/env dotnet // ํ์ค ๋ฐฉ์
///usr/bin/env dotnet "$0" "$@" ; exit $? // JBang ์คํ์ผ๋ฌธ์ : Permission denied ์ค๋ฅ ๋ฐ์
ํด๊ฒฐ:
chmod +x <ํ์ผ๋ช
>.cs๋ฌธ์ : ํจํค์ง๋ฅผ ์ฐพ์ ์ ์๊ฑฐ๋ ๋ฒ์ ์ถฉ๋
ํด๊ฒฐ:
# NuGet ์บ์ ์ ๋ฆฌ
dotnet nuget locals all --clear
# ๋ค์ ์คํ
./<ํ์ผ๋ช
>.cs๋ฌธ์ : Native AOT ์ปดํ์ผ ์ค ์ค๋ฅ ๋ฐ์
ํด๊ฒฐ:
- ํ๋ซํผ์ ๋ง๋ ๋น๋ ๋๊ตฌ ์ค์น ํ์
- macOS: Xcode Command Line Tools (
xcode-select --install) - Linux: GCC/Clang ๋ฐ ๊ฐ๋ฐ ๋ผ์ด๋ธ๋ฌ๋ฆฌ
- Windows: Visual Studio Build Tools
๋ฌธ์ : Dashboard์ ์ฐ๊ฒฐํ ์ ์์
ํด๊ฒฐ:
# ํฌํธ ์ถฉ๋ ํ์ธ
lsof -i :18888
# 03-apphost.json์์ ํฌํธ ๋ณ๊ฒฝ ๊ฐ๋ฅ๋ฌธ์ : openrouter-key is missing ์ค๋ฅ
ํด๊ฒฐ:
# User Secrets ์ค์ ํ์ธ
dotnet user-secrets list --id 06-agui-server
# ๋ค์ ์ค์
dotnet user-secrets --id 06-agui-server set openrouter-key "your-api-key"์ด ํ๋ก์ ํธ์ ๊ธฐ์ฌํ๊ณ ์ถ์ผ์ ๊ฐ์? ํ์ํฉ๋๋ค!
- ์ด ์ ์ฅ์๋ฅผ Fork ํ์ธ์
- Feature ๋ธ๋์น๋ฅผ ์์ฑํ์ธ์ (
git checkout -b feature/AmazingFeature) - ๋ณ๊ฒฝ์ฌํญ์ ์ปค๋ฐํ์ธ์ (
git commit -m 'Add some AmazingFeature') - ๋ธ๋์น์ Push ํ์ธ์ (
git push origin feature/AmazingFeature) - Pull Request๋ฅผ ์ด์ด์ฃผ์ธ์
๊ธฐ์ฌ ์์ด๋์ด:
- ์๋ก์ด ์์ ์ถ๊ฐ (gRPC, SignalR, Blazor ๋ฑ)
- ๊ธฐ์กด ์์ ๊ฐ์ ๋ฐ ๋ฒ๊ทธ ์์
- ๋ฌธ์ ๋ฒ์ญ (์์ด, ์ผ๋ณธ์ด ๋ฑ)
- ์ฑ๋ฅ ์ต์ ํ
- ํ ์คํธ ์ฝ๋ ์ถ๊ฐ
์ด ํ๋ก์ ํธ๋ MIT ๋ผ์ด์ ์ค ํ์ ๋ฐฐํฌ๋ฉ๋๋ค.
MIT License
Copyright (c) 2025
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
- .NET File-Based Applications - ๊ณต์ FBA ๋ฌธ์
- .NET 10 Release Notes - ์ต์ ๊ธฐ๋ฅ ๋ฐ ๋ณ๊ฒฝ์ฌํญ
- .NET Aspire Documentation - ํด๋ผ์ฐ๋ ๋ค์ดํฐ๋ธ ์ฑ ๊ตฌ์ถ
- Avalonia UI Documentation - ํฌ๋ก์ค ํ๋ซํผ UI ํ๋ ์์ํฌ
- Native AOT Deployment - ๋ค์ดํฐ๋ธ ์ปดํ์ผ ๊ฐ์ด๋
- Microsoft Agents AI - AI ์์ด์ ํธ ํ๋ ์์ํฌ
- OpenRouter - ํตํฉ LLM API ๊ฒ์ดํธ์จ์ด
- Garnet - Microsoft์ Redis ํธํ ์บ์
- LINQPad - .NET ๊ฐ๋ฐ ๋ฐ ์ฟผ๋ฆฌ ๋๊ตฌ
- .NET Community - ๊ณต์ ์ปค๋ฎค๋ํฐ
- Avalonia Community - Avalonia ์ปค๋ฎค๋ํฐ
- r/dotnet - Reddit ์ปค๋ฎค๋ํฐ
- dotnet/runtime - .NET ๋ฐํ์ ์์ค์ฝ๋
- dotnet/aspire - .NET Aspire ์์ค์ฝ๋
- AvaloniaUI/Avalonia - Avalonia UI ์์ค์ฝ๋
โญ ์ด ํ๋ก์ ํธ๊ฐ ๋์์ด ๋์ จ๋ค๋ฉด Star๋ฅผ ๋๋ฌ์ฃผ์ธ์!
๐ฌ ์ง๋ฌธ์ด๋ ์ ์์ฌํญ์ด ์์ผ์๋ฉด Issue๋ฅผ ์์ฑํด ์ฃผ์ธ์.