Try   HackMD

Ubuntu Linux 開發 dotnet 程式記錄

在 Claude Code 協助下試過了多個組合,把目前比較穩定的作法整理一下;為了避免在正式 Windows 環境中出現預期外的錯誤,基本上會讓執行環境盡可能接近正式環境。

  1. 使用 Docker 建立執行環境 https://github.com/dockur/windows
    1. 在裡面安裝與啟用 IIS ,然後讓 80 port 可以直接在外部存取
  2. 使用 Docker 建立 MSSQL https://learn.microsoft.com/zh-tw/sql/linux/quickstart-install-connect-docker?view=sql-server-ver17&tabs=cli&pivots=cs1-bash
    1. 建議一定要使用固定 IP ,否則每次重啟容器 IP 會跳
  3. .NET Core SDK https://snapcraft.io/install/dotnet-sdk/ubuntu
  4. 安裝 sqlcmd https://learn.microsoft.com/zh-tw/sql/linux/sql-server-linux-setup-tools?view=sql-server-ver16
#!/bin/bash
# setup-network.sh

# Create a custom Docker network for SQL Server and Windows containers
docker network create --driver bridge windows-sql-network 2>/dev/null || echo "Network already exists"

echo "Docker network 'windows-sql-network' is ready"
#!/bin/bash
# start-sql.sh

# Load environment variables
if [ -f .env ]; then
    export $(cat .env | grep -v '^#' | xargs)
fi

# Ensure the network exists
./setup-network.sh

# Start SQL Server container on the shared network with fixed IP
docker run -e "ACCEPT_EULA=Y" -e "MSSQL_SA_PASSWORD=${MSSQL_SA_PASSWORD}" \
  -e "MSSQL_RUN_AS_ROOT=1" \
  -e "MSSQL_MEMORY_LIMIT_MB=2048" \
  -e "MSSQL_NUMA_NODES=1" \
  -e "SQLPAL_TELEMETRY_DISABLED=1" \
  --name sql1 \
  --hostname sql1 \
  --network windows-sql-network \
  --ip 172.21.0.10 \
  -p 1433:1433 -d \
  --cpuset-cpus="0" \
  -u 0:0 \
  -v $(pwd)/sql:/var/opt/mssql \
  mcr.microsoft.com/mssql/server:2025-latest

#!/bin/bash
# start-windows.sh

# Load environment variables
if [ -f .env ]; then
    export $(cat .env | grep -v '^#' | xargs)
fi

# Ensure the network exists
./setup-network.sh

# Start Windows container with IIS and network connectivity to SQL Server with fixed IP
docker run -it --rm \
  --name windows \
  --network windows-sql-network \
  --ip ${WINDOWS_SERVER_IP} \
  -p 8006:8006 \
  -p 8011:80 \
  -p 8012:443 \
  --device=/dev/kvm \
  --device=/dev/net/tun \
  --cap-add NET_ADMIN \
  -v "./windows:/storage" \
  -v "./data:/data" \
  --stop-timeout 120 \
  -e "MSSQL_HOST=${MSSQL_SERVER_IP}" \
  -e "MSSQL_PORT=${MSSQL_SERVER_PORT}" \
  -e "MSSQL_USER=sa" \
  -e "MSSQL_PASSWORD=${MSSQL_SA_PASSWORD}" \
  dockurr/windows

# .env
# MSSQL Configuration
MSSQL_SA_PASSWORD={your password}
MSSQL_DATABASE={your db}
MSSQL_SERVER_IP=172.21.0.10
MSSQL_SERVER_PORT=1433

# Windows Container Configuration  
WINDOWS_SERVER_IP=172.21.0.20
DOCKER_NETWORK=windows-sql-network
#!/bin/bash
# scripts/build-backend.sh

echo "Building Backend on Linux for Windows Docker Container..."

# Set paths (script is in scripts/, project root is parent directory)
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_PATH="$(dirname "$SCRIPT_DIR")"
LOG_FILE="$PROJECT_PATH/build-log.txt"

# Start logging
echo "Build started at $(date)" > "$LOG_FILE"
echo "==================================" >> "$LOG_FILE"

# Change to project directory
cd "$PROJECT_PATH"
echo "Working directory: $(pwd)"
echo "Working directory: $(pwd)" >> "$LOG_FILE"

# Check .NET SDK
echo "Checking .NET SDK..."
echo "Checking .NET SDK..." >> "$LOG_FILE"
if ! dotnet --version >> "$LOG_FILE" 2>&1; then
    echo "ERROR: .NET SDK not found!"
    echo "ERROR: .NET SDK not found!" >> "$LOG_FILE"
    exit 1
fi

# Clean previous builds
echo "Cleaning previous builds..."
echo "Cleaning previous builds..." >> "$LOG_FILE"
rm -rf bin obj 2>/dev/null

# Restore packages
echo "Restoring NuGet packages..."
echo "Restoring NuGet packages..." >> "$LOG_FILE"
if ! dotnet restore >> "$LOG_FILE" 2>&1; then
    echo "ERROR: Package restore failed!"
    echo "ERROR: Package restore failed!" >> "$LOG_FILE"
    exit 1
fi
echo "Restore successful!"
echo "Restore successful!" >> "$LOG_FILE"

# Build application
echo "Building application..."
echo "Building application..." >> "$LOG_FILE"
if ! dotnet build --configuration Release --no-restore --verbosity normal >> "$LOG_FILE" 2>&1; then
    echo "ERROR: Build failed!"
    echo "ERROR: Build failed!" >> "$LOG_FILE"
    exit 1
fi
echo "Build successful!"
echo "Build successful!" >> "$LOG_FILE"

# Copy build output to project root for IIS
echo "Copying build output to project root..."
echo "Copying build output to project root..." >> "$LOG_FILE"

BUILD_OUTPUT="$PROJECT_PATH/bin/Release/net8.0"

if [ -d "$BUILD_OUTPUT" ]; then
    # Copy main application files
    cp -f "$BUILD_OUTPUT/Backend.dll" "$PROJECT_PATH/" 2>/dev/null
    cp -f "$BUILD_OUTPUT/Backend.deps.json" "$PROJECT_PATH/" 2>/dev/null
    cp -f "$BUILD_OUTPUT/Backend.runtimeconfig.json" "$PROJECT_PATH/" 2>/dev/null
    cp -f "$BUILD_OUTPUT/Backend.pdb" "$PROJECT_PATH/" 2>/dev/null
    cp -f "$BUILD_OUTPUT/web.config" "$PROJECT_PATH/" 2>/dev/null
    
    # Copy all dependency DLLs
    cp -f "$BUILD_OUTPUT"/*.dll "$PROJECT_PATH/" 2>/dev/null
    
    # Copy appsettings.json if it exists in build output
    cp -f "$BUILD_OUTPUT/appsettings.json" "$PROJECT_PATH/" 2>/dev/null || true
    
    # Copy runtimes folder for dependencies
    if [ -d "$BUILD_OUTPUT/runtimes" ]; then
        rm -rf "$PROJECT_PATH/runtimes" 2>/dev/null
        cp -r "$BUILD_OUTPUT/runtimes" "$PROJECT_PATH/" 2>/dev/null
    fi
    
    echo "✓ Build output copied successfully"
    echo "✓ Build output copied successfully" >> "$LOG_FILE"
else
    echo "ERROR: Build output directory not found: $BUILD_OUTPUT"
    echo "ERROR: Build output directory not found: $BUILD_OUTPUT" >> "$LOG_FILE"
    exit 1
fi

# Force IIS to reload by touching web.config or recycling app pool
echo "Forcing IIS application reload..."
echo "Forcing IIS application reload..." >> "$LOG_FILE"

# Method 1: Touch web.config to trigger reload
if [ -f "web.config" ]; then
    touch web.config
    echo "✓ web.config touched to trigger reload"
    echo "✓ web.config touched to trigger reload" >> "$LOG_FILE"
fi

# Method 2: Try to recycle app pool via Docker exec (if container name is known)
CONTAINER_NAME="windows"  # Your Windows Docker container name
if command -v docker >/dev/null 2>&1; then
    if docker ps --format "table {{.Names}}" | grep -q "^${CONTAINER_NAME}$"; then
        echo "Attempting to recycle IIS application pool via Docker..."
        echo "Attempting to recycle IIS application pool via Docker..." >> "$LOG_FILE"
        
        if docker exec "$CONTAINER_NAME" powershell -Command "Import-Module WebAdministration; Restart-WebAppPool -Name 'backend'" 2>/dev/null; then
            echo "✓ Application pool recycled successfully"
            echo "✓ Application pool recycled successfully" >> "$LOG_FILE"
        else
            echo "⚠ Could not recycle app pool (will rely on file change detection)"
            echo "⚠ Could not recycle app pool (will rely on file change detection)" >> "$LOG_FILE"
        fi
    else
        echo "⚠ Docker container '$CONTAINER_NAME' not found"
        echo "⚠ Docker container '$CONTAINER_NAME' not found" >> "$LOG_FILE"
    fi
fi

# Verify deployment
echo "Verifying deployment..."
echo "Verifying deployment..." >> "$LOG_FILE"
DEPLOY_OK=1

if [ -f "Backend.dll" ]; then
    echo "✓ Backend.dll deployed successfully"
    echo "✓ Backend.dll deployed successfully" >> "$LOG_FILE"
else
    echo "✗ Backend.dll deployment failed!"
    echo "✗ Backend.dll deployment failed!" >> "$LOG_FILE"
    DEPLOY_OK=0
fi

if [ -f "web.config" ]; then
    echo "✓ web.config deployed successfully"
    echo "✓ web.config deployed successfully" >> "$LOG_FILE"
else
    echo "✗ web.config deployment failed!"
    echo "✗ web.config deployment failed!" >> "$LOG_FILE"
    DEPLOY_OK=0
fi

if [ -f "appsettings.json" ]; then
    echo "✓ appsettings.json deployed successfully"
    echo "✓ appsettings.json deployed successfully" >> "$LOG_FILE"
else
    echo "✗ appsettings.json deployment failed!"
    echo "✗ appsettings.json deployment failed!" >> "$LOG_FILE"
    DEPLOY_OK=0
fi

if [ -d "Views" ] && [ -f "Views/_ViewStart.cshtml" ]; then
    echo "✓ Views deployed successfully"
    echo "✓ Views deployed successfully" >> "$LOG_FILE"
else
    echo "✗ Views deployment failed!"
    echo "✗ Views deployment failed!" >> "$LOG_FILE"
    DEPLOY_OK=0
fi

if [ $DEPLOY_OK -eq 0 ]; then
    echo ""
    echo "ERROR: Deployment verification failed!"
    echo "ERROR: Deployment verification failed!" >> "$LOG_FILE"
    echo "Please check the build log for details."
    exit 1
fi

echo ""
echo "SUCCESS! Backend application built and deployed successfully."
echo "SUCCESS! Backend application built and deployed successfully." >> "$LOG_FILE"
echo "Build completed at $(date)" >> "$LOG_FILE"
echo ""
echo "Next steps:"
echo "1. Application should automatically reload due to file changes"
echo "2. Access main interface at: http://localhost:8011/backend/"
echo "3. Individual table interfaces at: http://localhost:8011/backend/TableName/"
echo "4. Migration commands: dotnet run -- migrate <command>"
echo ""

exit 0