Skip to main content

Overview

This guide covers deployment options for Sistema Venta API, including IIS, Azure App Service, Docker containers, and self-hosted scenarios.

Pre-Deployment Checklist

1
Step 1: Configure Production Settings
2
Create or update appsettings.Production.json:
3
{
  "Logging": {
    "LogLevel": {
      "Default": "Warning",
      "Microsoft.AspNetCore": "Warning",
      "Microsoft.EntityFrameworkCore": "Warning"
    }
  },
  "AllowedHosts": "yourdomain.com",
  "ConnectionStrings": {
    "cadenaSQL": "${SQL_CONNECTION_STRING}"
  }
}
4
Step 2: Update CORS Policy
5
Restrict CORS to your frontend domain in Program.cs:14:
6
builder.Services.AddCors(options => {
    options.AddPolicy("NuevaPolitica", app => {
        app.WithOrigins("https://yourdomain.com", "https://www.yourdomain.com")
           .AllowAnyHeader()
           .AllowAnyMethod()
           .AllowCredentials();
    });
});
7
Never use AllowAnyOrigin() in production. Always specify exact origins.
8
Step 3: Enable HTTPS Redirection
9
Add HTTPS redirection middleware:
10
var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseHttpsRedirection();
}

app.UseCors("NuevaPolitica");
app.UseAuthorization();
app.MapControllers();
11
Step 4: Secure Connection Strings
12
Use environment variables or secrets management instead of plain text.
13
Step 5: Build Release Configuration
14
Build the project in Release mode:
15
dotnet build --configuration Release

Deployment Options

Option 1: IIS (Internet Information Services)

1
Install Prerequisites
2
  • Install .NET 7 Hosting Bundle from Microsoft:
  • Enable IIS features:
    • Open “Turn Windows features on or off”
    • Enable “Internet Information Services”
    • Enable “World Wide Web Services” → “Application Development Features” → “ASP.NET 4.8”
  • 3
    Publish the Application
    4
    cd APISistemaVenta/SistemaVenta.API
    dotnet publish --configuration Release --output ./publish
    
    5
    This creates a publish folder with all necessary files.
    6
    Configure IIS
    7
  • Open IIS Manager (inetmgr.exe)
  • Right-click SitesAdd Website
  • Configure:
    • Site name: SistemaVentaAPI
    • Physical path: Path to your publish folder
    • Binding:
      • Type: https
      • Port: 443
      • Host name: api.yourdomain.com
    • SSL certificate: Select or import your SSL certificate
  • Set Application Pool:
    • Right-click your site → Manage WebsiteAdvanced Settings
    • Application Pool: Create new pool
    • .NET CLR Version: No Managed Code
    • Managed Pipeline Mode: Integrated
  • 8
    Configure Application Pool Identity
    9
  • Go to Application Pools
  • Select your pool → Advanced Settings
  • Identity:
    • For SQL Windows Auth: Use ApplicationPoolIdentity or domain account
    • Grant this identity access to SQL Server
  • 10
    Set Environment Variables
    11
  • Select your site in IIS Manager
  • Open Configuration Editor
  • Section: system.webServer/aspNetCore
  • Add environment variables:
    <environmentVariables>
      <environmentVariable name="ASPNETCORE_ENVIRONMENT" value="Production" />
      <environmentVariable name="SQL_CONNECTION_STRING" value="Your-Connection-String" />
    </environmentVariables>
    
  • 12
    Test Deployment
    13
    Navigate to https://api.yourdomain.com/swagger (if Swagger is enabled) or test your API endpoints.
    Troubleshooting IIS:
    • Check Event Viewer → Windows Logs → Application for errors
    • Enable detailed errors: Set ASPNETCORE_ENVIRONMENT=Development temporarily
    • Verify .NET Hosting Bundle is installed: Check for aspnetcorev2.dll in IIS modules
    • Ensure application pool identity has file system permissions

    Option 2: Azure App Service

    1
    Create Azure Resources
    2
  • Create Azure SQL Database:
  • 3
    az sql server create \
      --name sistemaventa-sql \
      --resource-group your-resource-group \
      --location eastus \
      --admin-user sqladmin \
      --admin-password YourStrongPassword123!
    
    az sql db create \
      --resource-group your-resource-group \
      --server sistemaventa-sql \
      --name DBVENTA \
      --service-objective S0
    
    4
  • Create App Service:
  • 5
    az appservice plan create \
      --name sistemaventa-plan \
      --resource-group your-resource-group \
      --sku B1 \
      --is-linux
    
    az webapp create \
      --resource-group your-resource-group \
      --plan sistemaventa-plan \
      --name sistemaventa-api \
      --runtime "DOTNET|7.0"
    
    6
    Configure Connection String
    7
    Add connection string as Application Setting:
    8
    az webapp config connection-string set \
      --resource-group your-resource-group \
      --name sistemaventa-api \
      --settings cadenaSQL="Server=tcp:sistemaventa-sql.database.windows.net,1433;Database=DBVENTA;User ID=sqladmin;Password=YourStrongPassword123!;Encrypt=True;" \
      --connection-string-type SQLAzure
    
    9
    Deploy Using Visual Studio
    10
  • Right-click SistemaVenta.API project → Publish
  • Select AzureAzure App Service (Linux)
  • Sign in and select your App Service
  • Click Publish
  • 11
    Deploy Using Azure CLI
    12
    # Build and publish
    dotnet publish --configuration Release --output ./publish
    
    # Create deployment package
    cd publish
    zip -r deploy.zip .
    
    # Deploy to Azure
    az webapp deployment source config-zip \
      --resource-group your-resource-group \
      --name sistemaventa-api \
      --src deploy.zip
    
    13
    Configure App Settings
    14
    In Azure Portal:
    15
  • Go to your App Service
  • ConfigurationApplication settings
  • Add:
    • ASPNETCORE_ENVIRONMENT = Production
    • WEBSITE_RUN_FROM_PACKAGE = 1
  • ConfigurationGeneral settings
    • Stack: .NET
    • Major version: 7
    • HTTPS Only: On
  • 16
    Enable Logging
    17
    az webapp log config \
      --resource-group your-resource-group \
      --name sistemaventa-api \
      --application-logging filesystem \
      --level information
    
    # View logs
    az webapp log tail \
      --resource-group your-resource-group \
      --name sistemaventa-api
    
    Azure Pricing Considerations:
    • B1 App Service Plan: ~$13/month
    • S0 SQL Database: ~$15/month
    • Consider Azure SQL Database serverless tier for development

    Option 3: Docker Container

    1
    Create Dockerfile
    2
    Create Dockerfile in the solution root:
    3
    # Build stage
    FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build
    WORKDIR /src
    
    # Copy project files
    COPY ["SistemaVenta.API/SistemaVenta.API.csproj", "SistemaVenta.API/"]
    COPY ["SistemaVenta.BLL/SistemaVenta.BLL.csproj", "SistemaVenta.BLL/"]
    COPY ["SistemaVenta.DAL/SistemaVenta.DAL.csproj", "SistemaVenta.DAL/"]
    COPY ["SistemaVenta.DTO/SistemaVenta.DTO.csproj", "SistemaVenta.DTO/"]
    COPY ["SistemaVenta.IOC/SistemaVenta.IOC.csproj", "SistemaVenta.IOC/"]
    COPY ["SistemaVenta.Model/SistemaVenta.Model.csproj", "SistemaVenta.Model/"]
    COPY ["SistemaVenta.Utility/SistemaVenta.Utility.csproj", "SistemaVenta.Utility/"]
    
    # Restore dependencies
    RUN dotnet restore "SistemaVenta.API/SistemaVenta.API.csproj"
    
    # Copy everything else
    COPY . .
    
    # Build
    WORKDIR "/src/SistemaVenta.API"
    RUN dotnet build "SistemaVenta.API.csproj" -c Release -o /app/build
    
    # Publish
    FROM build AS publish
    RUN dotnet publish "SistemaVenta.API.csproj" -c Release -o /app/publish /p:UseAppHost=false
    
    # Runtime stage
    FROM mcr.microsoft.com/dotnet/aspnet:7.0 AS final
    WORKDIR /app
    EXPOSE 80
    EXPOSE 443
    
    COPY --from=publish /app/publish .
    ENTRYPOINT ["dotnet", "SistemaVenta.API.dll"]
    
    4
    Create docker-compose.yml
    5
    For local testing with SQL Server:
    6
    version: '3.8'
    
    services:
      api:
        build:
          context: .
          dockerfile: Dockerfile
        ports:
          - "5000:80"
        environment:
          - ASPNETCORE_ENVIRONMENT=Production
          - ConnectionStrings__cadenaSQL=Server=sqlserver;Database=DBVENTA;User Id=sa;Password=YourStrong@Password;TrustServerCertificate=True;
        depends_on:
          - sqlserver
        networks:
          - sistemaventa-network
    
      sqlserver:
        image: mcr.microsoft.com/mssql/server:2022-latest
        environment:
          - ACCEPT_EULA=Y
          - SA_PASSWORD=YourStrong@Password
          - MSSQL_PID=Express
        ports:
          - "1433:1433"
        volumes:
          - sqlserver-data:/var/opt/mssql
        networks:
          - sistemaventa-network
    
    volumes:
      sqlserver-data:
    
    networks:
      sistemaventa-network:
        driver: bridge
    
    7
    Build and Run
    8
    # Build the image
    docker build -t sistemaventa-api:latest .
    
    # Run with docker-compose
    docker-compose up -d
    
    # View logs
    docker-compose logs -f api
    
    # Stop services
    docker-compose down
    
    9
    Push to Container Registry
    10
    # Tag for Docker Hub
    docker tag sistemaventa-api:latest yourusername/sistemaventa-api:latest
    
    # Push to Docker Hub
    docker login
    docker push yourusername/sistemaventa-api:latest
    
    # Or push to Azure Container Registry
    az acr login --name yourregistry
    docker tag sistemaventa-api:latest yourregistry.azurecr.io/sistemaventa-api:latest
    docker push yourregistry.azurecr.io/sistemaventa-api:latest
    

    Option 4: Self-Hosted (Kestrel)

    1
    Publish Application
    2
    dotnet publish --configuration Release --runtime linux-x64 --self-contained false
    
    3
    Create Systemd Service (Linux)
    4
    Create /etc/systemd/system/sistemaventa-api.service:
    5
    [Unit]
    Description=Sistema Venta API
    After=network.target
    
    [Service]
    Type=notify
    User=www-data
    WorkingDirectory=/var/www/sistemaventa-api
    ExecStart=/usr/bin/dotnet /var/www/sistemaventa-api/SistemaVenta.API.dll
    Restart=always
    RestartSec=10
    KillSignal=SIGINT
    SyslogIdentifier=sistemaventa-api
    Environment=ASPNETCORE_ENVIRONMENT=Production
    Environment=DOTNET_PRINT_TELEMETRY_MESSAGE=false
    
    [Install]
    WantedBy=multi-user.target
    
    6
    Enable and start:
    7
    sudo systemctl enable sistemaventa-api
    sudo systemctl start sistemaventa-api
    sudo systemctl status sistemaventa-api
    
    8
    Configure Nginx as Reverse Proxy
    9
    Create /etc/nginx/sites-available/sistemaventa-api:
    10
    server {
        listen 80;
        listen [::]:80;
        server_name api.yourdomain.com;
        
        location / {
            return 301 https://$server_name$request_uri;
        }
    }
    
    server {
        listen 443 ssl http2;
        listen [::]:443 ssl http2;
        server_name api.yourdomain.com;
    
        ssl_certificate /etc/ssl/certs/yourdomain.crt;
        ssl_certificate_key /etc/ssl/private/yourdomain.key;
    
        location / {
            proxy_pass http://localhost:5000;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection keep-alive;
            proxy_set_header Host $host;
            proxy_cache_bypass $http_upgrade;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
        }
    }
    
    11
    Enable the site:
    12
    sudo ln -s /etc/nginx/sites-available/sistemaventa-api /etc/nginx/sites-enabled/
    sudo nginx -t
    sudo systemctl reload nginx
    

    Environment-Specific Configuration

    Development

    appsettings.Development.json
    {
      "Logging": {
        "LogLevel": {
          "Default": "Information",
          "Microsoft.AspNetCore": "Warning",
          "Microsoft.EntityFrameworkCore.Database.Command": "Information"
        }
      },
      "ConnectionStrings": {
        "cadenaSQL": "Server=localhost;Database=DBVENTA;Trusted_Connection=True;TrustServerCertificate=True;"
      }
    }
    

    Staging

    appsettings.Staging.json
    {
      "Logging": {
        "LogLevel": {
          "Default": "Information",
          "Microsoft.AspNetCore": "Warning"
        }
      },
      "ConnectionStrings": {
        "cadenaSQL": "${SQL_CONNECTION_STRING}"
      }
    }
    

    Production

    appsettings.Production.json
    {
      "Logging": {
        "LogLevel": {
          "Default": "Warning",
          "Microsoft.AspNetCore": "Warning"
        }
      },
      "AllowedHosts": "api.yourdomain.com",
      "ConnectionStrings": {
        "cadenaSQL": "${SQL_CONNECTION_STRING}"
      }
    }
    

    Security Best Practices

    1
    Step 1: Use HTTPS Only
    2
    if (!app.Environment.IsDevelopment())
    {
        app.UseHttpsRedirection();
        app.UseHsts();
    }
    
    3
    Step 2: Implement API Key Authentication
    4
    builder.Services.AddAuthentication("ApiKey")
        .AddScheme<ApiKeyAuthenticationOptions, ApiKeyAuthenticationHandler>("ApiKey", options => { });
    
    5
    Step 3: Add Rate Limiting
    6
    builder.Services.AddRateLimiter(options =>
    {
        options.AddFixedWindowLimiter("fixed", opt =>
        {
            opt.PermitLimit = 100;
            opt.Window = TimeSpan.FromMinutes(1);
        });
    });
    
    7
    Step 4: Enable Request Logging
    8
    app.UseHttpLogging();
    
    9
    Step 5: Sanitize Error Messages
    10
    Disable detailed errors in production (already configured in Program.cs).

    Health Checks

    Add health check endpoint:
    Program.cs
    builder.Services.AddHealthChecks()
        .AddDbContextCheck<DbventaContext>();
    
    app.MapHealthChecks("/health");
    
    Test: curl https://api.yourdomain.com/health

    Monitoring and Logging

    Application Insights (Azure)

    dotnet add package Microsoft.ApplicationInsights.AspNetCore
    
    Program.cs
    builder.Services.AddApplicationInsightsTelemetry(options =>
    {
        options.ConnectionString = builder.Configuration["ApplicationInsights:ConnectionString"];
    });
    

    Serilog

    dotnet add package Serilog.AspNetCore
    dotnet add package Serilog.Sinks.File
    
    Program.cs
    using Serilog;
    
    Log.Logger = new LoggerConfiguration()
        .WriteTo.File("logs/sistemaventa-.txt", rollingInterval: RollingInterval.Day)
        .CreateLogger();
    
    builder.Host.UseSerilog();
    

    Performance Optimization

    Enable Response Compression

    builder.Services.AddResponseCompression(options =>
    {
        options.EnableForHttps = true;
    });
    
    app.UseResponseCompression();
    

    Add Response Caching

    builder.Services.AddResponseCaching();
    app.UseResponseCaching();
    

    Enable Output Caching (.NET 7+)

    builder.Services.AddOutputCache();
    app.UseOutputCache();
    

    Rollback Strategy

    IIS

    1. Keep previous publish folder: publish-backup-{date}
    2. Update IIS site physical path to previous folder
    3. Restart application pool

    Azure App Service

    1. Go to Deployment slots
    2. Swap staging slot back to production
    3. Or use Deployment CenterLogsRedeploy previous version

    Docker

    # Tag versions
    docker tag sistemaventa-api:latest sistemaventa-api:v1.0.0
    
    # Rollback
    docker-compose down
    docker run -d sistemaventa-api:v1.0.0
    

    Post-Deployment Verification

    1
    Step 1: Test Health Endpoint
    2
    curl https://api.yourdomain.com/health
    
    3
    Step 2: Verify Database Connection
    4
    Test an API endpoint that queries the database.
    5
    Step 3: Check Swagger (if enabled)
    6
    curl https://api.yourdomain.com/swagger
    
    7
    Step 4: Monitor Logs
    8
    Check application logs for errors.
    9
    Step 5: Performance Test
    10
    Use tools like Apache Bench or k6 for load testing.

    Troubleshooting

    Causes:
    • Application pool stopped
    • .NET Hosting Bundle not installed
    • Application startup error
    Solutions:
    1. Check Event Viewer logs
    2. Enable stdout logging in web.config:
      <aspNetCore stdoutLogEnabled="true" stdoutLogFile=".\logs\stdout" />
      
    3. Verify application pool is running
    4. Restart IIS: iisreset
    Causes:
    • Incorrect connection string
    • Firewall blocking connection
    • SQL Server not accepting remote connections
    Solutions:
    1. Test connection string locally
    2. For Azure SQL: Add App Service IP to firewall rules
    3. Verify SQL Server TCP/IP is enabled
    4. Check connection string format
    Error: Access to fetch at 'https://api.yourdomain.com' from origin 'https://app.yourdomain.com' has been blocked by CORS policySolution: Update CORS policy in Program.cs:14 to include your frontend origin.

    Continuous Deployment

    GitHub Actions

    Create .github/workflows/deploy.yml:
    name: Deploy to Azure
    
    on:
      push:
        branches: [ main ]
    
    jobs:
      build-and-deploy:
        runs-on: ubuntu-latest
        
        steps:
        - uses: actions/checkout@v3
        
        - name: Setup .NET
          uses: actions/setup-dotnet@v3
          with:
            dotnet-version: '7.0.x'
        
        - name: Restore dependencies
          run: dotnet restore
        
        - name: Build
          run: dotnet build --configuration Release --no-restore
        
        - name: Test
          run: dotnet test --no-restore --verbosity normal
        
        - name: Publish
          run: dotnet publish -c Release -o ${{env.DOTNET_ROOT}}/publish
        
        - name: Deploy to Azure Web App
          uses: azure/webapps-deploy@v2
          with:
            app-name: 'sistemaventa-api'
            publish-profile: ${{ secrets.AZURE_WEBAPP_PUBLISH_PROFILE }}
            package: ${{env.DOTNET_ROOT}}/publish
    

    Next Steps

    Configuration

    Review configuration and dependency injection

    Database Setup

    Configure Entity Framework and database

    Build docs developers (and LLMs) love