Skip to content

Instantly share code, notes, and snippets.

@weehong
Last active November 1, 2025 05:12
Show Gist options
  • Select an option

  • Save weehong/dd5c3935e81d6d6784aea8456bf1acf7 to your computer and use it in GitHub Desktop.

Select an option

Save weehong/dd5c3935e81d6d6784aea8456bf1acf7 to your computer and use it in GitHub Desktop.
This script create a .NET project utilizing project structure
#!/bin/bash
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Configuration (Project name can be provided as CLI argument)
PROJECT_NAME=$1
INCLUDE_TESTS=true
DATABASE_PROVIDER="sqlserver"
DOTNET_VERSION="net9.0"
SCRIPT_DIR="$(pwd)"
print_info() { echo -e "${GREEN}✓${NC} $1"; }
print_error() { echo -e "${RED}✗${NC} $1"; }
print_warning() { echo -e "${YELLOW}⚠${NC} $1"; }
print_step() { echo -e "${BLUE}▶${NC} $1"; }
handle_error() {
print_error "An error occurred on line $1"
print_error "Command: $2"
exit 1
}
trap 'handle_error $LINENO "$BASH_COMMAND"' ERR
check_dotnet_version() {
if ! command -v dotnet &> /dev/null; then
print_error ".NET SDK is not installed. Install .NET 9.0 SDK first."
exit 1
fi
}
validate_project_name() { [[ $1 =~ ^[a-zA-Z][a-zA-Z0-9._-]*$ ]]; }
get_project_configuration() {
echo "========================================"
echo " Clean Architecture CQRS Setup"
echo " .NET 9.0 Production-Ready"
echo "========================================"
echo ""
if [ -z "$PROJECT_NAME" ]; then
if [ -t 0 ]; then
while true; do
read -rp "Enter project name: " PROJECT_NAME
[ -z "$PROJECT_NAME" ] && { print_error "Project name cannot be empty."; continue; }
validate_project_name "$PROJECT_NAME" || { print_error "Invalid project name."; continue; }
[ -d "$PROJECT_NAME" ] && { print_error "Directory already exists."; exit 1; }
break
done
else
print_error "No project name provided, and no interactive terminal available."
echo "Usage: $0 <ProjectName>"
exit 1
fi
else
print_info "Using project name: $PROJECT_NAME"
fi
read -rp "Include test projects? (Y/n): " include_tests
INCLUDE_TESTS=${include_tests:-Y}
echo ""
echo "Select database provider:"
echo " 1) SQL Server (default)"
echo " 2) PostgreSQL"
echo " 3) SQLite"
read -rp "Enter choice [1-3]: " db_choice
case ${db_choice:-1} in
1) DATABASE_PROVIDER="sqlserver" ;;
2) DATABASE_PROVIDER="postgresql" ;;
3) DATABASE_PROVIDER="sqlite" ;;
*) DATABASE_PROVIDER="sqlserver" ;;
esac
}
create_directory_structure() {
print_step "Creating directory structure..."
mkdir -p "$PROJECT_NAME"/src
[[ $INCLUDE_TESTS =~ ^[Yy]$ ]] && mkdir -p "$PROJECT_NAME"/tests
cd "$PROJECT_NAME"
print_info "Directory structure created"
}
create_solution() {
print_step "Creating solution..."
dotnet new sln -n "$PROJECT_NAME" --force
print_info "Solution created"
}
create_project() {
dotnet new "$1" -n "$2" -f "$DOTNET_VERSION" -o "$3" --force
dotnet sln "$PROJECT_NAME.sln" add "$3/$2.csproj"
echo " ✓ $2"
}
create_source_projects() {
print_step "Creating source projects..."
create_project classlib "$PROJECT_NAME.Domain" src/$PROJECT_NAME.Domain
create_project classlib "$PROJECT_NAME.Application" src/$PROJECT_NAME.Application
create_project classlib "$PROJECT_NAME.Infrastructure" src/$PROJECT_NAME.Infrastructure
create_project classlib "$PROJECT_NAME.Contracts" src/$PROJECT_NAME.Contracts
dotnet new webapi -n "$PROJECT_NAME.API" -f "$DOTNET_VERSION" -o src/$PROJECT_NAME.API --use-controllers --force
dotnet sln "$PROJECT_NAME.sln" add src/$PROJECT_NAME.API/$PROJECT_NAME.API.csproj
print_info "Source projects created"
}
create_test_projects() {
[[ ! $INCLUDE_TESTS =~ ^[Yy]$ ]] && return
print_step "Creating test projects..."
create_project xunit "$PROJECT_NAME.Domain.Tests" tests/$PROJECT_NAME.Domain.Tests
create_project xunit "$PROJECT_NAME.Application.Tests" tests/$PROJECT_NAME.Application.Tests
create_project xunit "$PROJECT_NAME.Infrastructure.Tests" tests/$PROJECT_NAME.Infrastructure.Tests
create_project xunit "$PROJECT_NAME.API.Tests" tests/$PROJECT_NAME.API.Tests
print_info "Test projects created"
}
add_reference() { local project=$1; shift; for ref in "$@"; do dotnet add "$project" reference "$ref"; done; }
add_project_references() {
print_step "Adding project references..."
# Application depends on Domain + Contracts
add_reference src/$PROJECT_NAME.Application/$PROJECT_NAME.Application.csproj \
src/$PROJECT_NAME.Domain/$PROJECT_NAME.Domain.csproj \
src/$PROJECT_NAME.Contracts/$PROJECT_NAME.Contracts.csproj
# Infrastructure depends on Application + Domain + Contracts
add_reference src/$PROJECT_NAME.Infrastructure/$PROJECT_NAME.Infrastructure.csproj \
src/$PROJECT_NAME.Application/$PROJECT_NAME.Application.csproj \
src/$PROJECT_NAME.Domain/$PROJECT_NAME.Domain.csproj \
src/$PROJECT_NAME.Contracts/$PROJECT_NAME.Contracts.csproj
# API depends on everything except tests
add_reference src/$PROJECT_NAME.API/$PROJECT_NAME.API.csproj \
src/$PROJECT_NAME.Application/$PROJECT_NAME.Application.csproj \
src/$PROJECT_NAME.Infrastructure/$PROJECT_NAME.Infrastructure.csproj \
src/$PROJECT_NAME.Contracts/$PROJECT_NAME.Contracts.csproj
}
add_package() { dotnet add "$1" package "$2"; }
install_mediatr_packages() {
print_step "Installing MediatR..."
add_package src/$PROJECT_NAME.Application/$PROJECT_NAME.Application.csproj "MediatR"
}
install_serilog_packages() {
print_step "Installing Serilog..."
add_package src/$PROJECT_NAME.API/$PROJECT_NAME.API.csproj "Serilog.AspNetCore"
}
install_ef_packages() {
print_step "Installing EF Core..."
add_package src/$PROJECT_NAME.Infrastructure/$PROJECT_NAME.Infrastructure.csproj "Microsoft.EntityFrameworkCore"
case $DATABASE_PROVIDER in
sqlserver) add_package src/$PROJECT_NAME.Infrastructure/$PROJECT_NAME.Infrastructure.csproj "Microsoft.EntityFrameworkCore.SqlServer" ;;
postgresql) add_package src/$PROJECT_NAME.Infrastructure/$PROJECT_NAME.Infrastructure.csproj "Npgsql.EntityFrameworkCore.PostgreSQL" ;;
sqlite) add_package src/$PROJECT_NAME.Infrastructure/$PROJECT_NAME.Infrastructure.csproj "Microsoft.EntityFrameworkCore.Sqlite" ;;
esac
}
install_production_packages() {
print_step "Installing FluentValidation and AutoMapper..."
add_package src/$PROJECT_NAME.Application/$PROJECT_NAME.Application.csproj "FluentValidation"
add_package src/$PROJECT_NAME.Application/$PROJECT_NAME.Application.csproj "AutoMapper"
}
install_test_packages() {
[[ ! $INCLUDE_TESTS =~ ^[Yy]$ ]] && return
print_step "Installing test packages..."
for proj in tests/*/*.csproj; do
add_package "$proj" "FluentAssertions"
add_package "$proj" "Moq"
done
}
cleanup_default_files() {
print_step "Cleaning up defaults..."
find . -name "WeatherForecast*" -delete 2>/dev/null
find . -name "Class1.cs" -delete 2>/dev/null
}
create_configuration_files() {
print_step "Creating README.md..."
echo "# $PROJECT_NAME" > README.md
}
build_solution() {
print_step "Building solution..."
dotnet build
print_info "Build successful!"
}
display_summary() {
echo ""
print_info "Setup Complete!"
echo "cd $PROJECT_NAME/src/$PROJECT_NAME.API && dotnet run"
}
main() {
clear
check_dotnet_version
get_project_configuration
create_directory_structure
create_solution
create_source_projects
create_test_projects
add_project_references
install_mediatr_packages
install_serilog_packages
install_ef_packages
install_production_packages
install_test_packages
cleanup_default_files
create_configuration_files
build_solution
display_summary
}
main
#!/bin/bash
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
PROJECT_NAME=$1
INCLUDE_TESTS=true
DATABASE_PROVIDER="sqlserver"
DOTNET_VERSION="net9.0"
print_info() { echo -e "${GREEN}✓${NC} $1"; }
print_error() { echo -e "${RED}✗${NC} $1"; }
print_warning() { echo -e "${YELLOW}⚠${NC} $1"; }
print_step() { echo -e "${BLUE}▶${NC} $1"; }
trap 'print_error "Error on line $LINENO: $BASH_COMMAND"; exit 1' ERR
check_requirements() {
command -v dotnet >/dev/null || { print_error ".NET SDK missing."; exit 1; }
command -v jq >/dev/null || { print_error "'jq' is required. Install via apt/brew."; exit 1; }
}
validate_project_name() { [[ $1 =~ ^[a-zA-Z][a-zA-Z0-9._-]*$ ]]; }
get_project_configuration() {
if [ -z "$PROJECT_NAME" ]; then
read -rp "Enter project name: " PROJECT_NAME
validate_project_name "$PROJECT_NAME" || { print_error "Invalid project name."; exit 1; }
[ -d "$PROJECT_NAME" ] && { print_error "Directory exists."; exit 1; }
fi
read -rp "Include test projects? (Y/n): " include_tests
INCLUDE_TESTS=${include_tests:-Y}
echo ""
echo "Select database provider:"
echo "1) SQL Server (default)"
echo "2) PostgreSQL"
echo "3) SQLite"
read -rp "Choice [1-3]: " db_choice
case ${db_choice:-1} in
1) DATABASE_PROVIDER="sqlserver" ;;
2) DATABASE_PROVIDER="postgresql" ;;
3) DATABASE_PROVIDER="sqlite" ;;
esac
}
create_structure() {
print_step "Creating folder structure..."
mkdir -p "$PROJECT_NAME"/src "$PROJECT_NAME"/tests
cd "$PROJECT_NAME"
print_info "Structure created."
}
create_solution() {
print_step "Creating solution..."
dotnet new sln -n "$PROJECT_NAME" --force
}
create_project() {
dotnet new "$1" -n "$2" -f "$DOTNET_VERSION" -o "$3" --force
dotnet sln add "$3/$2.csproj"
}
create_projects() {
print_step "Creating source projects..."
create_project classlib "$PROJECT_NAME.Domain" src/$PROJECT_NAME.Domain
create_project classlib "$PROJECT_NAME.Application" src/$PROJECT_NAME.Application
create_project classlib "$PROJECT_NAME.Infrastructure" src/$PROJECT_NAME.Infrastructure
create_project classlib "$PROJECT_NAME.Contracts" src/$PROJECT_NAME.Contracts
dotnet new webapi -n "$PROJECT_NAME.API" -f "$DOTNET_VERSION" -o src/$PROJECT_NAME.API --use-controllers --force
dotnet sln add src/$PROJECT_NAME.API/$PROJECT_NAME.API.csproj
if [[ $INCLUDE_TESTS =~ ^[Yy]$ ]]; then
print_step "Creating test projects..."
create_project xunit "$PROJECT_NAME.Application.Tests" tests/$PROJECT_NAME.Application.Tests
create_project xunit "$PROJECT_NAME.Infrastructure.Tests" tests/$PROJECT_NAME.Infrastructure.Tests
fi
}
add_reference() { local proj=$1; shift; for ref in "$@"; do dotnet add "$proj" reference "$ref"; done; }
configure_references() {
print_step "Adding project references..."
add_reference src/$PROJECT_NAME.Application/$PROJECT_NAME.Application.csproj \
src/$PROJECT_NAME.Domain/$PROJECT_NAME.Domain.csproj \
src/$PROJECT_NAME.Contracts/$PROJECT_NAME.Contracts.csproj
add_reference src/$PROJECT_NAME.Infrastructure/$PROJECT_NAME.Infrastructure.csproj \
src/$PROJECT_NAME.Application/$PROJECT_NAME.Application.csproj \
src/$PROJECT_NAME.Domain/$PROJECT_NAME.Domain.csproj \
src/$PROJECT_NAME.Contracts/$PROJECT_NAME.Contracts.csproj
add_reference src/$PROJECT_NAME.API/$PROJECT_NAME.API.csproj \
src/$PROJECT_NAME.Application/$PROJECT_NAME.Application.csproj \
src/$PROJECT_NAME.Infrastructure/$PROJECT_NAME.Infrastructure.csproj \
src/$PROJECT_NAME.Contracts/$PROJECT_NAME.Contracts.csproj
}
get_latest_nuget_version() {
local package="$1"
curl -s "https://api.nuget.org/v3-flatcontainer/${package,,}/index.json" | jq -r '.versions[-1]'
}
add_package() {
local project="$1"
local package="$2"
local version
version=$(get_latest_nuget_version "$package")
if [[ -n "$version" && "$version" != "null" ]]; then
print_step "$package v$version → $project"
dotnet add "$project" package "$package" --version "$version"
else
print_warning "$package version not found, auto-resolving."
dotnet add "$project" package "$package"
fi
}
install_packages() {
print_step "Installing Application Layer packages..."
add_package src/$PROJECT_NAME.Application/$PROJECT_NAME.Application.csproj "MediatR"
add_package src/$PROJECT_NAME.Application/$PROJECT_NAME.Application.csproj "MediatR.Extensions.Microsoft.DependencyInjection"
add_package src/$PROJECT_NAME.Application/$PROJECT_NAME.Application.csproj "FluentValidation"
add_package src/$PROJECT_NAME.Application/$PROJECT_NAME.Application.csproj "FluentValidation.DependencyInjectionExtensions"
add_package src/$PROJECT_NAME.Application/$PROJECT_NAME.Application.csproj "AutoMapper"
add_package src/$PROJECT_NAME.Application/$PROJECT_NAME.Application.csproj "AutoMapper.Extensions.Microsoft.DependencyInjection"
print_step "Installing Infrastructure Layer packages..."
add_package src/$PROJECT_NAME.Infrastructure/$PROJECT_NAME.Infrastructure.csproj "Microsoft.EntityFrameworkCore"
case $DATABASE_PROVIDER in
sqlserver) add_package src/$PROJECT_NAME.Infrastructure/$PROJECT_NAME.Infrastructure.csproj "Microsoft.EntityFrameworkCore.SqlServer" ;;
postgresql) add_package src/$PROJECT_NAME.Infrastructure/$PROJECT_NAME.Infrastructure.csproj "Npgsql.EntityFrameworkCore.PostgreSQL" ;;
sqlite) add_package src/$PROJECT_NAME.Infrastructure/$PROJECT_NAME.Infrastructure.csproj "Microsoft.EntityFrameworkCore.Sqlite" ;;
esac
add_package src/$PROJECT_NAME.Infrastructure/$PROJECT_NAME.Infrastructure.csproj "Serilog"
add_package src/$PROJECT_NAME.Infrastructure/$PROJECT_NAME.Infrastructure.csproj "Serilog.Sinks.Console"
add_package src/$PROJECT_NAME.Infrastructure/$PROJECT_NAME.Infrastructure.csproj "Serilog.Sinks.File"
print_step "Installing API Layer packages..."
add_package src/$PROJECT_NAME.API/$PROJECT_NAME.API.csproj "Serilog.AspNetCore"
add_package src/$PROJECT_NAME.API/$PROJECT_NAME.API.csproj "Serilog.Settings.Configuration"
add_package src/$PROJECT_NAME.API/$PROJECT_NAME.API.csproj "Asp.Versioning.Http"
}
cleanup() {
print_step "Removing template files..."
find . -name "WeatherForecast*" -delete
find . -name "Class1.cs" -delete
}
finish() {
print_info "Setup Complete ✅"
echo "Run the API:"
echo "cd src/$PROJECT_NAME.API && dotnet run"
}
main() {
clear
check_requirements
get_project_configuration
create_structure
create_solution
create_projects
configure_references
install_packages
cleanup
finish
}
main
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment