.NET: Deployment, Performance & Interview Questions
Publishing & Docker
# Publish for production
dotnet publish -c Release -o ./publish
# Self-contained (no runtime needed on target)
dotnet publish -c Release -r linux-x64 --self-contained -o ./publish
# Single file executable
dotnet publish -c Release -r linux-x64 --self-contained -p:PublishSingleFile=true -o ./publish# Multi-stage Dockerfile
FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build
WORKDIR /src
COPY *.csproj ./
RUN dotnet restore
COPY . .
RUN dotnet publish -c Release -o /app/publish
FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS runtime
WORKDIR /app
COPY --from=build /app/publish .
EXPOSE 8080
ENV ASPNETCORE_URLS=http://+:8080
ENTRYPOINT ["dotnet", "MyApi.dll"]Performance Tips
Use async/await throughout — never block on async code with .Result or .Wait()
AsNoTracking() on EF queries that don't need change tracking — significant performance gain for read-heavy endpoints
Response compression: app.UseResponseCompression() — cuts JSON payload 60-80%
Output caching (ASP.NET Core 7+): [OutputCache(Duration = 60)] — server-side caching without client changes
IMemoryCache / IDistributedCache (Redis): cache expensive queries or computed results
Minimal APIs are slightly faster than controller-based (less overhead) — but controllers are easier to organize
Span<T> and ArrayPool<T>: avoid allocations in hot paths — reduces GC pressure
Use CancellationToken everywhere — allows request cancellation to propagate to DB queries
Testing
// xUnit + Moq
public class UserServiceTests
{
private readonly Mock<IUserRepository> _repoMock = new();
private readonly UserService _sut;
public UserServiceTests()
{
_sut = new UserService(_repoMock.Object, Mock.Of<ILogger<UserService>>());
}
[Fact]
public async Task GetByIdAsync_WhenUserExists_ReturnsDto()
{
var user = new User { Id = 1, Name = "Alice", Email = "alice@example.com" };
_repoMock.Setup(r => r.GetByIdAsync(1)).ReturnsAsync(user);
var result = await _sut.GetByIdAsync(1);
Assert.NotNull(result);
Assert.Equal("Alice", result.Name);
}
// Integration test with WebApplicationFactory
public class ApiIntegrationTests : IClassFixture<WebApplicationFactory<Program>>
{
private readonly HttpClient _client;
public ApiIntegrationTests(WebApplicationFactory<Program> factory)
{
_client = factory.WithWebHostBuilder(builder => {
builder.ConfigureServices(services => {
// Replace real DB with in-memory for tests
services.AddDbContext<AppDbContext>(opts =>
opts.UseInMemoryDatabase("TestDb"));
});
}).CreateClient();
}
[Fact]
public async Task GetUsers_ReturnsOk()
{
var response = await _client.GetAsync("/api/users");
response.EnsureSuccessStatusCode();
}
}
}Interview Questions
What is the difference between .NET Framework and .NET (Core)? .NET Framework is Windows-only, legacy. .NET 5+ is cross-platform, open-source, and the future.
What is the CLR? Common Language Runtime — manages memory (GC), JIT compilation, exception handling, and thread management.
Explain GC generations. Gen 0 (short-lived), Gen 1 (medium), Gen 2 (long-lived). GC promotes objects that survive collections. Large objects (>85KB) go to the LOH.
What is the difference between IEnumerable and IQueryable? IEnumerable executes in-memory; IQueryable translates to SQL (via EF). Always finish EF queries with ToList() to materialize.
Explain async/await internals. await captures the continuation and returns control to the caller. The state machine resumes when the awaited task completes — no thread is blocked.
What is the difference between Transient, Scoped, and Singleton? Transient: new per injection. Scoped: one per HTTP request. Singleton: one per app lifetime.
What is middleware? Pipeline components that handle HTTP requests/responses. Each calls next() to pass to the next component or short-circuits.
What are value types vs reference types? Value types (struct, int, bool) stored on stack — copied on assignment. Reference types (class) stored on heap — shared reference.
Keep your own version of these notes — editable, searchable, and organised by your stack.
Start free