Skip to main content

On This Page

Deploying .NET 8 APIs for Free: A Guide to Render, Supabase, and Upstash Integration

3 min read
Share

These articles are AI-generated summaries. Please check the original sources for full details.

I Deployed a .NET 8 URL Shortener for Free — Here’s Every Problem I Hit

Syed Hassan successfully deployed a .NET 8 URL shortener using a fully free stack of Render, Supabase, and Upstash. This implementation achieves production-quality architecture at $0/month but highlights critical hurdles in cloud connectivity and scope management.

Why This Matters

The transition from local development to free-tier cloud hosting often uncovers hidden infrastructure constraints, such as IPv4-only environments failing to connect to IPv6-ready databases. Furthermore, standard ASP.NET Core behaviors, like DI scope disposal, can break background tasks that work perfectly in a development environment, necessitating a deeper understanding of IServiceScopeFactory to prevent runtime exceptions.

Key Insights

  • Supabase direct connections fail on IPv4 hosts like Render; the Session Pooler is required with the ‘postgres.PROJECT_REF’ username format.
  • Npgsql 9.x discontinued support for URI-format connection strings, requiring the use of standard keyword formats like ‘Host=’ or ‘Server=’ consistently.
  • Background tasks executed as fire-and-forget will trigger an ObjectDisposedException unless a new scope is manually created via IServiceScopeFactory.
  • Render free tier services sleep after 15 minutes of inactivity, causing a 30-second latency spike on initial requests after a spin-down.
  • Implementing caching as a decorator with Scrutor keeps the Application layer clean and independent of the caching strategy, allowing zero-knowledge service layers.
  • Prometheus-net.AspNetCore integration enables real-time observability for HTTP request duration and endpoint-level throughput.

Working Examples

Using Scrutor to implement caching as a decorator on the repository, ensuring services have zero knowledge of the caching logic.

services.AddScoped<IUrlRepository, UrlRepository>();
services.Decorate<IUrlRepository, CachedUrlRepository>();

Multi-stage Dockerfile optimized for Render, ensuring dependencies are restored before full source copy to leverage layer caching.

FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /app
COPY solidshortener.sln .
COPY src/SolidShortener.Domain/SolidShortener.Domain.csproj src/SolidShortener.Domain/
COPY src/SolidShortener.Application/SolidShortener.Application.csproj src/SolidShortener.Application/
COPY src/SolidShortener.Infrastructure/SolidShortener.Infrastructure.csproj src/SolidShortener.Infrastructure/
COPY src/SolidShortener.Api/SolidShortener.Api.csproj src/SolidShortener.Api/
RUN dotnet restore src/SolidShortener.Api/SolidShortener.Api.csproj
COPY src/ src/
RUN dotnet publish src/SolidShortener.Api/SolidShortener.Api.csproj -c Release -o out
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS runtime
WORKDIR /app
COPY --from=build /app/out .
ENV ASPNETCORE_URLS=http://+:8080
EXPOSE 8080
ENTRYPOINT ["dotnet", "SolidShortener.Api.dll"]

Correct implementation of fire-and-forget background tasks using IServiceScopeFactory to avoid ObjectDisposedException.

_ = Task.Run(async () =>
{
    using var scope = _scopeFactory.CreateScope();
    var visitService = scope.ServiceProvider.GetRequiredService<IVisitService>();
    try
    {
        await visitService.LogVisitAsync(command);
    }
    catch (Exception ex)
    {
        _logger.LogError(ex, "Failed to log visit for {ShortCode}", code);
    }
});

Practical Applications

  • System: Background analytics logging; Behavior: Uses Task.Run to log visits independently of request lifecycle. Pitfall: Discarding the task without creating a new scope leads to ObjectDisposedException when the request scope ends.
  • System: Production API Error Handling; Behavior: Generic error middleware returns ex.Message. Pitfall: Npgsql exceptions leak full connection strings and passwords to the client in 500 responses.
  • System: Dockerized .NET Builds; Behavior: Restoring the full solution file via RUN dotnet restore. Pitfall: Build fails if the Docker context does not include test projects referenced in the .sln file.
  • System: URL Shortener API; Behavior: Uses Base62 encoding on auto-increment IDs for short codes. Pitfall: Sequential IDs allow users to iterate through and discover all stored URLs via simple incrementation.

References:

Continue reading

Next article

Intro to tc Cloud Functors: Graph-First Serverless Infrastructure

Related Content