Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 68 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# .dockerignore for NLWebNet
# Exclude files and directories that should not be copied to Docker context

# Git and development files
.git/
.gitignore
.gitattributes
.github/
*.md
docs/
doc/

# IDE and editor files
.vs/
.vscode/
*.swp
*.swo
*~

# Build outputs
**/bin/
**/obj/
**/out/
**/publish/

# Test results
TestResults/
*.trx
*.coverage
*.coveragexml

# Packages
*.nupkg
*.snupkg
packages/

# User secrets and environment files
.env
.env.*
**/secrets.json

# Temporary files
tmp/
temp/
*.tmp
*.temp

# OS generated files
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
ehthumbs.db
Thumbs.db

# Node.js (if any)
node_modules/
npm-debug.log*

# Logs
logs/
*.log

# Runtime directories
var/
etc/
usr/
63 changes: 63 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# Multi-stage Dockerfile for NLWebNet Demo Application
# Optimized for .NET 9 with security hardening and minimal attack surface

# Build stage
FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build
WORKDIR /src

# Configure NuGet to trust certificates and use HTTPS
ENV NUGET_XMLDOC_MODE=skip
ENV DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1
ENV DOTNET_NOLOGO=1

# Copy project files for efficient layer caching
COPY ["demo/NLWebNet.Demo.csproj", "demo/"]
COPY ["src/NLWebNet/NLWebNet.csproj", "src/NLWebNet/"]
COPY ["NLWebNet.sln", "./"]

# Restore dependencies with better error handling
RUN dotnet restore "demo/NLWebNet.Demo.csproj" --verbosity minimal

# Copy source code
COPY . .

# Build the application
WORKDIR "/src/demo"
RUN dotnet build "NLWebNet.Demo.csproj" -c Release -o /app/build --no-restore

# Publish stage
FROM build AS publish
RUN dotnet publish "NLWebNet.Demo.csproj" -c Release -o /app/publish --no-restore --no-build

# Runtime stage
FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS runtime
WORKDIR /app

# Install curl for health checks
RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*

# Create non-root user for security
RUN groupadd -r nlwebnet && useradd -r -g nlwebnet nlwebnet

# Copy published application
COPY --from=publish /app/publish .

# Set ownership to non-root user
RUN chown -R nlwebnet:nlwebnet /app

# Switch to non-root user
USER nlwebnet

# Expose port
EXPOSE 8080

# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -f http://localhost:8080/health || exit 1

# Set environment variables for production
ENV ASPNETCORE_ENVIRONMENT=Production
ENV ASPNETCORE_URLS=http://+:8080

# Entry point
ENTRYPOINT ["dotnet", "NLWebNet.Demo.dll"]
32 changes: 32 additions & 0 deletions NLWebNet.sln
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "demo", "demo", "{A39C23D2-F
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NLWebNet.Demo", "demo\NLWebNet.Demo.csproj", "{6F25FD99-AF67-4509-A46C-FCD450F6A775}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NLWebNet.Demo.AppHost", "demo-apphost\NLWebNet.Demo.AppHost.csproj", "{B8F2A1E3-9CFA-4D1B-8B2E-1234567890AB}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "shared", "shared", "{C4B5D6E7-8F9A-4B5C-9D8E-234567890ABC}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServiceDefaults", "shared\ServiceDefaults\ServiceDefaults.csproj", "{D5E6F7A8-9B0C-4D5E-8F9A-345678901BCD}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{0AB3BF05-4346-4AA6-1389-037BE0695223}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NLWebNet.Tests", "tests\NLWebNet.Tests\NLWebNet.Tests.csproj", "{21F486B2-CB3A-4D61-8C1F-FBCE3CA48CFE}"
Expand Down Expand Up @@ -49,6 +55,30 @@ Global
{6F25FD99-AF67-4509-A46C-FCD450F6A775}.Release|x64.Build.0 = Release|Any CPU
{6F25FD99-AF67-4509-A46C-FCD450F6A775}.Release|x86.ActiveCfg = Release|Any CPU
{6F25FD99-AF67-4509-A46C-FCD450F6A775}.Release|x86.Build.0 = Release|Any CPU
{B8F2A1E3-9CFA-4D1B-8B2E-1234567890AB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B8F2A1E3-9CFA-4D1B-8B2E-1234567890AB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B8F2A1E3-9CFA-4D1B-8B2E-1234567890AB}.Debug|x64.ActiveCfg = Debug|Any CPU
{B8F2A1E3-9CFA-4D1B-8B2E-1234567890AB}.Debug|x64.Build.0 = Debug|Any CPU
{B8F2A1E3-9CFA-4D1B-8B2E-1234567890AB}.Debug|x86.ActiveCfg = Debug|Any CPU
{B8F2A1E3-9CFA-4D1B-8B2E-1234567890AB}.Debug|x86.Build.0 = Debug|Any CPU
{B8F2A1E3-9CFA-4D1B-8B2E-1234567890AB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B8F2A1E3-9CFA-4D1B-8B2E-1234567890AB}.Release|Any CPU.Build.0 = Release|Any CPU
{B8F2A1E3-9CFA-4D1B-8B2E-1234567890AB}.Release|x64.ActiveCfg = Release|Any CPU
{B8F2A1E3-9CFA-4D1B-8B2E-1234567890AB}.Release|x64.Build.0 = Release|Any CPU
{B8F2A1E3-9CFA-4D1B-8B2E-1234567890AB}.Release|x86.ActiveCfg = Release|Any CPU
{B8F2A1E3-9CFA-4D1B-8B2E-1234567890AB}.Release|x86.Build.0 = Release|Any CPU
{D5E6F7A8-9B0C-4D5E-8F9A-345678901BCD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D5E6F7A8-9B0C-4D5E-8F9A-345678901BCD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D5E6F7A8-9B0C-4D5E-8F9A-345678901BCD}.Debug|x64.ActiveCfg = Debug|Any CPU
{D5E6F7A8-9B0C-4D5E-8F9A-345678901BCD}.Debug|x64.Build.0 = Debug|Any CPU
{D5E6F7A8-9B0C-4D5E-8F9A-345678901BCD}.Debug|x86.ActiveCfg = Debug|Any CPU
{D5E6F7A8-9B0C-4D5E-8F9A-345678901BCD}.Debug|x86.Build.0 = Debug|Any CPU
{D5E6F7A8-9B0C-4D5E-8F9A-345678901BCD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D5E6F7A8-9B0C-4D5E-8F9A-345678901BCD}.Release|Any CPU.Build.0 = Release|Any CPU
{D5E6F7A8-9B0C-4D5E-8F9A-345678901BCD}.Release|x64.ActiveCfg = Release|Any CPU
{D5E6F7A8-9B0C-4D5E-8F9A-345678901BCD}.Release|x64.Build.0 = Release|Any CPU
{D5E6F7A8-9B0C-4D5E-8F9A-345678901BCD}.Release|x86.ActiveCfg = Release|Any CPU
{D5E6F7A8-9B0C-4D5E-8F9A-345678901BCD}.Release|x86.Build.0 = Release|Any CPU
{21F486B2-CB3A-4D61-8C1F-FBCE3CA48CFE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{21F486B2-CB3A-4D61-8C1F-FBCE3CA48CFE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{21F486B2-CB3A-4D61-8C1F-FBCE3CA48CFE}.Debug|x64.ActiveCfg = Debug|Any CPU
Expand All @@ -68,6 +98,8 @@ Global
GlobalSection(NestedProjects) = preSolution
{1E458E72-D542-44BB-9F84-1EDE008FBB1D} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B}
{6F25FD99-AF67-4509-A46C-FCD450F6A775} = {A39C23D2-F2C0-258D-165A-CF1E7FEE6E7B}
{B8F2A1E3-9CFA-4D1B-8B2E-1234567890AB} = {A39C23D2-F2C0-258D-165A-CF1E7FEE6E7B}
{21F486B2-CB3A-4D61-8C1F-FBCE3CA48CFE} = {0AB3BF05-4346-4AA6-1389-037BE0695223}
{D5E6F7A8-9B0C-4D5E-8F9A-345678901BCD} = {C4B5D6E7-8F9A-4B5C-9D8E-234567890ABC}
EndGlobalSection
EndGlobal
95 changes: 90 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -188,34 +188,59 @@ app.MapNLWebNet(); // Map NLWebNet minimal API endpoints

### Prerequisites

- .NET 9.0 SDK
- .NET 8.0 SDK or later
- .NET Aspire workload (recommended): `dotnet workload install aspire`
- Visual Studio 2022 or VS Code

### Running the Demo

#### 🌟 Recommended: .NET Aspire (with observability dashboard)

1. **Clone the repository**

```bash
git clone https://github.com/jongalloway/NLWebNet.git
cd NLWebNet
```

2. **Build the solution**
2. **Install .NET Aspire workload** (one-time setup)

```bash
dotnet workload install aspire
```

3. **Run with Aspire orchestration**

```bash
cd demo-apphost
dotnet run
```

4. **Access the applications**
- **Aspire Dashboard**: `https://localhost:15888` (monitoring, logs, metrics)
- **Demo UI**: `http://localhost:8080`
- **Swagger UI**: `http://localhost:8080/swagger`

#### Traditional: Standalone Demo

1. **Clone and build**

```bash
git clone https://github.com/jongalloway/NLWebNet.git
cd NLWebNet
dotnet build
```

3. **Run the demo application**
2. **Run the demo application**

```bash
cd demo
dotnet run
```

4. **Open your browser**
3. **Open your browser**
- Demo UI: `http://localhost:5037`
- OpenAPI Spec: `http://localhost:5037/openapi/v1.json`
- Swagger UI: `http://localhost:5037/swagger`

5. **Test the demo features**
- **Home Page**: Overview and navigation to demo features
Expand Down Expand Up @@ -308,6 +333,66 @@ curl -X POST "http://localhost:5037/mcp" \
-d '{"method": "list_tools"}'
```

## πŸš€ Deployment

NLWebNet supports multiple deployment strategies for various environments:

### 🌟 Recommended: .NET Aspire

**.NET Aspire is the recommended approach** for .NET developers building cloud-native applications:

```bash
# Development with full observability
cd demo-apphost
dotnet run

# Access Aspire dashboard at https://localhost:15888
# Access demo app at http://localhost:8080
```

**Benefits:**
- Built-in observability and telemetry
- Service discovery and configuration management
- Production-ready health checks and resilience patterns
- Integrated development experience with dashboard

πŸ“– **[Complete Aspire Integration Guide](doc/aspire-integration.md)**

### Quick Start - Docker

```bash
# Build and test the Docker image
docker build -t nlwebnet-demo .
docker run -p 8080:8080 nlwebnet-demo

# Or use Docker Compose for development
docker-compose up --build
```

### Production Deployment Options

- **🐳 Docker & Docker Compose** - Containerized deployment with development and production configurations
- **☸️ Kubernetes** - Scalable container orchestration with auto-scaling and health checks
- **🌐 Azure Container Apps** - Serverless container platform with automatic scaling
- **🌍 Azure App Service** - Platform-as-a-Service deployment with integrated monitoring
- **πŸ“¦ Helm Charts** - Package manager for Kubernetes with templated deployments

### Deployment Guides

- **[Complete Deployment Guide](doc/deployment-guide.md)** - Comprehensive instructions for all platforms
- **[Deployment Scripts](deployment/scripts/)** - Automated deployment scripts
- **[Kubernetes Manifests](deployment/kubernetes/)** - Ready-to-use K8s configurations
- **[Azure Templates](deployment/azure/)** - ARM templates for Azure deployment
- **[Helm Chart](deployment/helm/nlwebnet-demo/)** - Production-ready Helm chart

### Health Monitoring

All deployments include:
- Health check endpoint at `/health`
- Liveness and readiness probes
- Application performance monitoring
- Structured logging and observability

## βš™οΈ Configuration

NLWebNet uses standard ASP.NET Core configuration patterns for managing settings and external service credentials.
Expand Down
20 changes: 20 additions & 0 deletions demo-apphost/NLWebNet.Demo.AppHost.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<OutputType>Exe</OutputType>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<UserSecretsId>aspire-nlwebnet-demo-apphost</UserSecretsId>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Aspire.Hosting" Version="8.0.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\demo\NLWebNet.Demo.csproj" />
<ProjectReference Include="..\shared\ServiceDefaults\ServiceDefaults.csproj" />
</ItemGroup>

</Project>
41 changes: 41 additions & 0 deletions demo-apphost/Program.Extended.cs.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
using Aspire.Hosting;

var builder = DistributedApplication.CreateBuilder(args);

// Example: Add Redis cache (uncomment to use)
// var redis = builder.AddRedis("cache");

// Example: Add PostgreSQL database (uncomment to use)
// var postgres = builder.AddPostgres("postgres")
// .WithEnvironment("POSTGRES_DB", "nlwebnet");
// var database = postgres.AddDatabase("nlwebnetdb");

// Add the NLWebNet Demo web application
var nlwebnetDemo = builder.AddProject("nlwebnet-demo", "../demo/NLWebNet.Demo.csproj")
.WithHttpEndpoint(port: 8080, name: "http")
.WithEnvironment("ASPNETCORE_ENVIRONMENT", builder.Environment.EnvironmentName)
.WithEnvironment("NLWebNet__DefaultMode", "List")
.WithEnvironment("NLWebNet__EnableStreaming", "true")
.WithEnvironment("NLWebNet__DefaultTimeoutSeconds", "30")
.WithEnvironment("NLWebNet__MaxResultsPerQuery", "50");

// Example: Connect to Redis cache
// nlwebnetDemo.WithReference(redis);

// Example: Connect to database
// nlwebnetDemo.WithReference(database);

// Example: Add a background service
// var backgroundService = builder.AddProject("nlwebnet-worker", "../worker/NLWebNet.Worker.csproj")
// .WithReference(database)
// .WithReference(redis);

// Example: Add an API gateway or reverse proxy
// var gateway = builder.AddProject("nlwebnet-gateway", "../gateway/NLWebNet.Gateway.csproj")
// .WithHttpEndpoint(port: 80, name: "public")
// .WithReference(nlwebnetDemo);

// Build and run the application
var app = builder.Build();

await app.RunAsync();
Loading
Loading