├── .dockerignore ├── .gitignore ├── WebApi ├── Program.cs ├── appsettings.Development.json ├── appsettings.json ├── nuget.config ├── WebApi.csproj ├── Dockerfile └── Properties │ └── launchSettings.json ├── WebApiChiseled ├── Program.cs ├── appsettings.Development.json ├── appsettings.json ├── nuget.config ├── Dockerfile ├── WebApi.csproj └── Properties │ └── launchSettings.json ├── GrpcApi ├── appsettings.Development.json ├── appsettings.json ├── nuget.config ├── Protos │ └── greet.proto ├── Services │ └── GreeterService.cs ├── Properties │ └── launchSettings.json ├── Program.cs ├── GrpcApi.csproj └── Dockerfile ├── OpenSslEmbedding ├── Program.cs ├── nuget.config ├── OpenSslEmbedding.csproj ├── Dockerfile └── Dockerfile.nossl ├── NpgCli ├── nuget.config ├── Program.cs ├── Dockerfile.noicu ├── Dockerfile └── NpgCli.csproj ├── EmbeddedICU ├── nuget.config ├── Program.cs ├── EmbeddedICU.csproj └── Dockerfile ├── NpgCliSlim ├── nuget.config ├── Program.cs ├── Dockerfile.noicu ├── Dockerfile └── NpgCliSlim.csproj ├── CompressionEmbedding ├── nuget.config ├── Dockerfile ├── CompressionEmbedding.csproj └── Program.cs ├── InvariantGlobalization ├── nuget.config ├── Program.cs ├── Dockerfile └── InvariantGlobalization.csproj ├── GrpcApiClient ├── Protos │ └── greet.proto ├── GrpcApiClient.csproj └── Program.cs ├── NativeAOTDocker.sln ├── calc.fsx └── README.md /.dockerignore: -------------------------------------------------------------------------------- 1 | bin/ 2 | obj/ 3 | out/ 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | bin/ 2 | obj/ 3 | out/ 4 | certs/ 5 | -------------------------------------------------------------------------------- /WebApi/Program.cs: -------------------------------------------------------------------------------- 1 | var builder = WebApplication.CreateBuilder(args); 2 | var app = builder.Build(); 3 | 4 | app.MapGet("/", () => "Hello World!"); 5 | 6 | app.Run(); 7 | -------------------------------------------------------------------------------- /WebApiChiseled/Program.cs: -------------------------------------------------------------------------------- 1 | var builder = WebApplication.CreateBuilder(args); 2 | var app = builder.Build(); 3 | 4 | app.MapGet("/", () => "Hello World!"); 5 | 6 | app.Run(); 7 | -------------------------------------------------------------------------------- /GrpcApi/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /WebApi/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /WebApiChiseled/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /WebApi/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | }, 8 | "AllowedHosts": "*" 9 | } 10 | -------------------------------------------------------------------------------- /WebApiChiseled/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | }, 8 | "AllowedHosts": "*" 9 | } 10 | -------------------------------------------------------------------------------- /GrpcApi/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | }, 8 | "AllowedHosts": "*", 9 | "Kestrel": { 10 | "EndpointDefaults": { 11 | "Protocols": "Http2" 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /OpenSslEmbedding/Program.cs: -------------------------------------------------------------------------------- 1 | Console.WriteLine("Querying first website:"); 2 | using var client = new HttpClient(); 3 | var content = await client.GetStringAsync("http://info.cern.ch/"); 4 | Console.WriteLine(content); 5 | 6 | Console.WriteLine("Querying website over HTTPS:"); 7 | content = await client.GetStringAsync("https://smallsrv.com/"); 8 | Console.WriteLine(content.Substring(0, 300)); 9 | -------------------------------------------------------------------------------- /GrpcApi/nuget.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /NpgCli/nuget.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /WebApi/nuget.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /EmbeddedICU/nuget.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /NpgCliSlim/nuget.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /WebApiChiseled/nuget.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /GrpcApi/Protos/greet.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | option csharp_namespace = "GrpcApi"; 4 | 5 | package greet; 6 | 7 | // The greeting service definition. 8 | service Greeter { 9 | // Sends a greeting 10 | rpc SayHello (HelloRequest) returns (HelloReply); 11 | } 12 | 13 | // The request message containing the user's name. 14 | message HelloRequest { 15 | string name = 1; 16 | } 17 | 18 | // The response message containing the greetings. 19 | message HelloReply { 20 | string message = 1; 21 | } 22 | -------------------------------------------------------------------------------- /OpenSslEmbedding/nuget.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /CompressionEmbedding/nuget.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /InvariantGlobalization/nuget.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /GrpcApiClient/Protos/greet.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | option csharp_namespace = "GrpcApiClient"; 4 | 5 | package greet; 6 | 7 | // The greeting service definition. 8 | service Greeter { 9 | // Sends a greeting 10 | rpc SayHello (HelloRequest) returns (HelloReply); 11 | } 12 | 13 | // The request message containing the user's name. 14 | message HelloRequest { 15 | string name = 1; 16 | } 17 | 18 | // The response message containing the greetings. 19 | message HelloReply { 20 | string message = 1; 21 | } 22 | -------------------------------------------------------------------------------- /CompressionEmbedding/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/dotnet/sdk:9.0-alpine AS build 2 | WORKDIR /app 3 | RUN apk add clang binutils musl-dev build-base zlib-static 4 | COPY nuget.config . 5 | COPY CompressionEmbedding.csproj . 6 | RUN dotnet restore --runtime linux-musl-x64 CompressionEmbedding.csproj 7 | 8 | COPY . . 9 | RUN dotnet publish -c Release -r linux-musl-x64 -o out CompressionEmbedding.csproj 10 | 11 | FROM scratch AS runtime 12 | WORKDIR /app 13 | COPY --from=build /app/out/CompressionEmbedding /app/ 14 | ENTRYPOINT ["/app/CompressionEmbedding"] 15 | -------------------------------------------------------------------------------- /InvariantGlobalization/Program.cs: -------------------------------------------------------------------------------- 1 | using System.Globalization; 2 | 3 | Console.WriteLine("There no globalization"); 4 | 5 | Console.WriteLine("Enter you name:"); 6 | var greeting = Console.ReadLine(); 7 | Console.WriteLine($"Hello {greeting}!"); 8 | double num = 5.2; 9 | 10 | var parsed = int.TryParse("-120", NumberStyles.Integer, CultureInfo.InvariantCulture, out var reversedOffset); 11 | Console.WriteLine($"Parsed -120 invariant culture: {parsed}, result is {reversedOffset}"); 12 | Console.WriteLine($"Number 5.2 with invariant culture {num.ToString("F2")}"); 13 | -------------------------------------------------------------------------------- /NpgCliSlim/Program.cs: -------------------------------------------------------------------------------- 1 | using Npgsql; 2 | 3 | var connectionString = Environment.GetEnvironmentVariable("ConnectionString") ?? "Host=localhost:32768;Username=postgres;Password=postgrespw"; 4 | Console.WriteLine("Connecting using connection string "+ connectionString); 5 | using var conn = new NpgsqlSlimDataSourceBuilder(connectionString).Build(); 6 | 7 | await using (var cmd = conn.CreateCommand("SELECT 5")) 8 | await using (var reader = await cmd.ExecuteReaderAsync()) 9 | { 10 | while (await reader.ReadAsync()) 11 | Console.WriteLine(reader.GetInt32(0)); 12 | } 13 | -------------------------------------------------------------------------------- /InvariantGlobalization/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/dotnet/sdk:9.0-alpine AS build 2 | WORKDIR /app 3 | RUN apk add clang binutils musl-dev build-base zlib-static 4 | COPY nuget.config . 5 | COPY InvariantGlobalization.csproj . 6 | RUN dotnet restore --runtime linux-musl-x64 InvariantGlobalization.csproj 7 | 8 | COPY . . 9 | RUN dotnet publish -c Release -r linux-musl-x64 -o out InvariantGlobalization.csproj 10 | 11 | FROM scratch AS runtime 12 | WORKDIR /app 13 | COPY --from=build /app/out/InvariantGlobalization /app/ 14 | ENTRYPOINT ["/app/InvariantGlobalization"] 15 | -------------------------------------------------------------------------------- /NpgCli/Program.cs: -------------------------------------------------------------------------------- 1 | using Npgsql; 2 | 3 | var connectionString = Environment.GetEnvironmentVariable("ConnectionString") ?? "Host=localhost:32768;Username=postgres;Password=postgrespw"; 4 | Console.WriteLine("Connecting using connection string "+ connectionString); 5 | await using var conn = new NpgsqlConnection(connectionString); 6 | await conn.OpenAsync(); 7 | 8 | await using (var cmd = new NpgsqlCommand("SELECT 5", conn)) 9 | await using (var reader = await cmd.ExecuteReaderAsync()) 10 | { 11 | while (await reader.ReadAsync()) 12 | Console.WriteLine(reader.GetInt32(0)); 13 | } 14 | -------------------------------------------------------------------------------- /WebApiChiseled/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/dotnet/sdk:9.0-noble AS build 2 | WORKDIR /app 3 | COPY nuget.config . 4 | COPY WebApi.csproj . 5 | RUN dotnet restore --runtime linux-x64 WebApi.csproj 6 | 7 | COPY . . 8 | RUN apt update && apt-get install -y clang zlib1g-dev 9 | RUN dotnet publish -c Release -r linux-x64 -o out WebApi.csproj 10 | 11 | FROM mcr.microsoft.com/dotnet/nightly/runtime-deps:9.0-noble-chiseled AS runtime 12 | WORKDIR /app 13 | COPY --from=build /app/out/WebApi /app/ 14 | ENV ASPNETCORE_URLS="http://+" 15 | EXPOSE 443 16 | EXPOSE 80 17 | ENTRYPOINT ["/app/WebApi"] 18 | -------------------------------------------------------------------------------- /EmbeddedICU/Program.cs: -------------------------------------------------------------------------------- 1 | using System.Globalization; 2 | 3 | Console.WriteLine("With globalizations"); 4 | 5 | Console.WriteLine("Enter you name:"); 6 | var greeting = Console.ReadLine(); 7 | Console.WriteLine($"Hello {greeting}!"); 8 | double num = 5.2; 9 | 10 | var parsed = int.TryParse("-120", NumberStyles.Integer, CultureInfo.InvariantCulture, out var reversedOffset); 11 | Console.WriteLine($"Parsed -120 invariant culture: {parsed}, result is {reversedOffset}"); 12 | Console.WriteLine($"Number 5.2 in ru-RU locale {num.ToString("F2", System.Globalization.CultureInfo.GetCultureInfo("ru-ru"))}"); 13 | -------------------------------------------------------------------------------- /GrpcApi/Services/GreeterService.cs: -------------------------------------------------------------------------------- 1 | using Grpc.Core; 2 | using GrpcApi; 3 | 4 | namespace GrpcApi.Services; 5 | 6 | public class GreeterService : Greeter.GreeterBase 7 | { 8 | private readonly ILogger _logger; 9 | public GreeterService(ILogger logger) 10 | { 11 | _logger = logger; 12 | } 13 | 14 | public override Task SayHello(HelloRequest request, ServerCallContext context) 15 | { 16 | return Task.FromResult(new HelloReply 17 | { 18 | Message = "Hello " + request.Name 19 | }); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /WebApiChiseled/WebApi.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net9.0 5 | enable 6 | enable 7 | true 8 | false 9 | true 10 | true 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /GrpcApi/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "http": { 4 | "commandName": "Project", 5 | "dotnetRunMessages": true, 6 | "launchBrowser": false, 7 | "applicationUrl": "http://localhost:5163", 8 | "environmentVariables": { 9 | "ASPNETCORE_ENVIRONMENT": "Development" 10 | } 11 | }, 12 | "https": { 13 | "commandName": "Project", 14 | "dotnetRunMessages": true, 15 | "launchBrowser": false, 16 | "applicationUrl": "https://localhost:7077;http://localhost:5163", 17 | "environmentVariables": { 18 | "ASPNETCORE_ENVIRONMENT": "Development" 19 | } 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /GrpcApi/Program.cs: -------------------------------------------------------------------------------- 1 | using GrpcApi.Services; 2 | 3 | var builder = WebApplication.CreateBuilder(args); 4 | 5 | // Additional configuration is required to successfully run gRPC on macOS. 6 | // For instructions on how to configure Kestrel and gRPC clients on macOS, visit https://go.microsoft.com/fwlink/?linkid=2099682 7 | 8 | // Add services to the container. 9 | builder.Services.AddGrpc(); 10 | 11 | var app = builder.Build(); 12 | 13 | // Configure the HTTP request pipeline. 14 | app.MapGrpcService(); 15 | app.MapGet("/", () => "Communication with gRPC endpoints must be made through a gRPC client. To learn how to create a client, visit: https://go.microsoft.com/fwlink/?linkid=2086909"); 16 | 17 | app.Run(); 18 | -------------------------------------------------------------------------------- /CompressionEmbedding/CompressionEmbedding.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net9.0 6 | enable 7 | true 8 | true 9 | true 10 | true 11 | true 12 | true 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /InvariantGlobalization/InvariantGlobalization.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net9.0 6 | enable 7 | true 8 | true 9 | true 10 | true 11 | true 12 | true 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /EmbeddedICU/EmbeddedICU.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net9.0 6 | enable 7 | true 8 | true 9 | true 10 | false 11 | true 12 | true 13 | true 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /WebApi/WebApi.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net9.0 5 | enable 6 | enable 7 | true 8 | true 9 | false 10 | true 11 | true 12 | true 13 | true 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /NpgCli/Dockerfile.noicu: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/dotnet/sdk:9.0-alpine AS build 2 | WORKDIR /app 3 | # these RUN lines below is optimization for current experiment to account for the fact that I have multiple similar configuration 4 | # best practices of Docker building imply that I put all dependencies in single line 5 | RUN apk add clang binutils musl-dev build-base zlib-static 6 | RUN apk add cmake 7 | RUN apk add openssl-dev openssl-libs-static 8 | COPY nuget.config . 9 | COPY NpgCli.csproj . 10 | RUN dotnet restore --runtime linux-musl-x64 NpgCli.csproj 11 | 12 | COPY . . 13 | RUN dotnet publish -c Release -r linux-musl-x64 -o out NpgCli.csproj /p:InvariantGlobalization=true 14 | 15 | FROM scratch AS runtime 16 | WORKDIR /app 17 | COPY --from=build /app/out/NpgCli /app/ 18 | ENTRYPOINT ["/app/NpgCli"] 19 | -------------------------------------------------------------------------------- /NpgCliSlim/Dockerfile.noicu: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/dotnet/sdk:9.0-alpine AS build 2 | WORKDIR /app 3 | # these RUN lines below is optimization for current experiment to account for the fact that I have multiple similar configuration 4 | # best practices of Docker building imply that I put all dependencies in single line 5 | RUN apk add clang binutils musl-dev build-base zlib-static 6 | RUN apk add cmake 7 | RUN apk add openssl-dev openssl-libs-static 8 | COPY nuget.config . 9 | COPY NpgCliSlim.csproj . 10 | RUN dotnet restore --runtime linux-musl-x64 NpgCliSlim.csproj 11 | 12 | COPY . . 13 | RUN dotnet publish -c Release -r linux-musl-x64 -o out NpgCliSlim.csproj /p:InvariantGlobalization=true 14 | 15 | FROM scratch AS runtime 16 | WORKDIR /app 17 | COPY --from=build /app/out/NpgCliSlim /app/ 18 | ENTRYPOINT ["/app/NpgCliSlim"] 19 | -------------------------------------------------------------------------------- /OpenSslEmbedding/OpenSslEmbedding.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net9.0 6 | enable 7 | true 8 | true 9 | false 10 | true 11 | true 12 | true 13 | true 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /GrpcApiClient/GrpcApiClient.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net7.0 6 | enable 7 | enable 8 | 9 | 10 | 11 | 12 | 13 | 14 | runtime; build; native; contentfiles; analyzers; buildtransitive 15 | all 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /EmbeddedICU/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/dotnet/sdk:9.0-alpine AS build 2 | WORKDIR /app 3 | # these RUN lines below is optimization for current experiment to account for the fact that I have multiple similar configuration 4 | # best practices of Docker building imply that I put all dependencies in single line 5 | RUN apk add clang binutils musl-dev build-base zlib-static 6 | RUN apk add cmake 7 | RUN apk add icu-static icu-dev 8 | COPY nuget.config . 9 | COPY EmbeddedICU.csproj . 10 | RUN dotnet restore --runtime linux-musl-x64 EmbeddedICU.csproj 11 | 12 | COPY . . 13 | RUN dotnet publish -c Release -r linux-musl-x64 -o out EmbeddedICU.csproj 14 | 15 | FROM scratch AS runtime 16 | WORKDIR /app 17 | COPY --from=build /app/out/EmbeddedICU /app/ 18 | COPY --from=build /usr/share/icu/74.2/icudt74l.dat /usr/share/icu/74.2/ 19 | ENTRYPOINT ["/app/EmbeddedICU"] 20 | -------------------------------------------------------------------------------- /NpgCli/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/dotnet/sdk:9.0-alpine AS build 2 | WORKDIR /app 3 | # these RUN lines below is optimization for current experiment to account for the fact that I have multiple similar configuration 4 | # best practices of Docker building imply that I put all dependencies in single line 5 | RUN apk add clang binutils musl-dev build-base zlib-static 6 | RUN apk add cmake 7 | RUN apk add icu-static icu-dev 8 | RUN apk add openssl-dev openssl-libs-static 9 | COPY nuget.config . 10 | COPY NpgCli.csproj . 11 | RUN dotnet restore --runtime linux-musl-x64 NpgCli.csproj 12 | 13 | COPY . . 14 | RUN dotnet publish -c Release -r linux-musl-x64 -o out NpgCli.csproj 15 | 16 | FROM scratch AS runtime 17 | WORKDIR /app 18 | COPY --from=build /app/out/NpgCli /app/ 19 | COPY --from=build /usr/share/icu/74.2/icudt74l.dat /usr/share/icu/74.2/ 20 | ENTRYPOINT ["/app/NpgCli"] 21 | -------------------------------------------------------------------------------- /WebApi/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/dotnet/sdk:9.0-alpine AS build 2 | WORKDIR /app 3 | # these RUN lines below is optimization for current experiment to account for the fact that I have multiple similar configuration 4 | # best practices of Docker building imply that I put all dependencies in single line 5 | RUN apk add clang binutils musl-dev build-base zlib-static 6 | RUN apk add cmake 7 | RUN apk add openssl-dev openssl-libs-static openssl 8 | COPY nuget.config . 9 | COPY WebApi.csproj . 10 | RUN dotnet restore --runtime linux-musl-x64 WebApi.csproj 11 | 12 | COPY . . 13 | RUN dotnet publish -c Release -r linux-musl-x64 -o out WebApi.csproj 14 | 15 | FROM scratch AS runtime 16 | WORKDIR /app 17 | COPY --from=build /app/out/WebApi /app/ 18 | COPY --from=build /etc/ssl/certs/* /etc/ssl/certs/ 19 | ENV ASPNETCORE_URLS="http://+" 20 | EXPOSE 443 21 | EXPOSE 80 22 | ENTRYPOINT ["/app/WebApi"] 23 | -------------------------------------------------------------------------------- /NpgCliSlim/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/dotnet/sdk:9.0-alpine AS build 2 | WORKDIR /app 3 | # these RUN lines below is optimization for current experiment to account for the fact that I have multiple similar configuration 4 | # best practices of Docker building imply that I put all dependencies in single line 5 | RUN apk add clang binutils musl-dev build-base zlib-static 6 | RUN apk add cmake 7 | RUN apk add icu-static icu-dev 8 | RUN apk add openssl-dev openssl-libs-static 9 | COPY nuget.config . 10 | COPY NpgCliSlim.csproj . 11 | RUN dotnet restore --runtime linux-musl-x64 NpgCliSlim.csproj 12 | 13 | COPY . . 14 | RUN dotnet publish -c Release -r linux-musl-x64 -o out NpgCliSlim.csproj 15 | 16 | FROM scratch AS runtime 17 | WORKDIR /app 18 | COPY --from=build /app/out/NpgCliSlim /app/ 19 | COPY --from=build /usr/share/icu/74.2/icudt74l.dat /usr/share/icu/74.2/ 20 | ENTRYPOINT ["/app/NpgCliSlim"] 21 | -------------------------------------------------------------------------------- /OpenSslEmbedding/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/dotnet/sdk:9.0-alpine AS build 2 | WORKDIR /app 3 | # these RUN lines below is optimization for current experiment to account for the fact that I have multiple similar configuration 4 | # best practices of Docker building imply that I put all dependencies in single line 5 | RUN apk add clang binutils musl-dev build-base zlib-static 6 | RUN apk add cmake 7 | RUN apk add openssl-dev openssl-libs-static 8 | COPY nuget.config . 9 | COPY OpenSslEmbedding.csproj . 10 | RUN dotnet restore --runtime linux-musl-x64 OpenSslEmbedding.csproj 11 | 12 | COPY . . 13 | RUN dotnet publish -c Release -r linux-musl-x64 -o out OpenSslEmbedding.csproj 14 | RUN strip /app/out/OpenSslEmbedding 15 | 16 | FROM scratch AS runtime 17 | WORKDIR /app 18 | COPY --from=build /app/out/OpenSslEmbedding /app/ 19 | COPY --from=build /etc/ssl/certs/* /etc/ssl/certs/ 20 | ENTRYPOINT ["/app/OpenSslEmbedding"] 21 | -------------------------------------------------------------------------------- /OpenSslEmbedding/Dockerfile.nossl: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/dotnet/sdk:9.0-alpine AS build 2 | WORKDIR /app 3 | # these RUN lines below is optimization for current experiment to account for the fact that I have multiple similar configuration 4 | # best practices of Docker building imply that I put all dependencies in single line 5 | RUN apk add clang binutils musl-dev build-base zlib-static 6 | RUN apk add cmake 7 | RUN apk add openssl-dev openssl-libs-static 8 | COPY nuget.config . 9 | COPY OpenSslEmbedding.csproj . 10 | RUN dotnet restore --runtime linux-musl-x64 OpenSslEmbedding.csproj 11 | 12 | COPY . . 13 | RUN dotnet publish -c Release -r linux-musl-x64 -o out OpenSslEmbedding.csproj /p:StaticOpenSslLinking=false 14 | RUN strip /app/out/OpenSslEmbedding 15 | 16 | FROM scratch AS runtime 17 | WORKDIR /app 18 | COPY --from=build /app/out/OpenSslEmbedding /app/ 19 | COPY --from=build /etc/ssl/certs/* /etc/ssl/certs/ 20 | ENTRYPOINT ["/app/OpenSslEmbedding"] 21 | -------------------------------------------------------------------------------- /GrpcApi/GrpcApi.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net9.0 5 | enable 6 | enable 7 | true 8 | true 9 | false 10 | true 11 | true 12 | true 13 | true 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /GrpcApiClient/Program.cs: -------------------------------------------------------------------------------- 1 | using System.Net; 2 | using System.Threading.Tasks; 3 | using Grpc.Net.Client; 4 | using GrpcApiClient; 5 | 6 | ServicePointManager.ServerCertificateValidationCallback += (o, c, ch, er) => true; 7 | 8 | // The port number must match the port of the gRPC server. 9 | var options = new GrpcChannelOptions(){ UnsafeUseInsecureChannelCallCredentials = true }; 10 | var httpClientHandler = new HttpClientHandler(); 11 | 12 | // That's only to simplify showing that GRPC channel woks 13 | // Remove from production code. 14 | httpClientHandler.ServerCertificateCustomValidationCallback = (message, cert, chain, _) => { 15 | return true; 16 | }; 17 | options.HttpHandler = httpClientHandler; 18 | 19 | using var channel = GrpcChannel.ForAddress("https://localhost:8011", options); 20 | var client = new Greeter.GreeterClient(channel); 21 | var reply = await client.SayHelloAsync( 22 | new HelloRequest { Name = "GreeterClient" }); 23 | Console.WriteLine("Greeting: " + reply.Message); 24 | Console.WriteLine("Press any key to exit..."); 25 | Console.ReadKey(); 26 | -------------------------------------------------------------------------------- /NpgCli/NpgCli.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net9.0 6 | enable 7 | enable 8 | true 9 | true 10 | false 11 | 12 | false 13 | true 14 | $(DefineConstants);NO_GLOBALIZATION 15 | true 16 | true 17 | true 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /NpgCliSlim/NpgCliSlim.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net9.0 6 | enable 7 | enable 8 | true 9 | true 10 | false 11 | 12 | false 13 | true 14 | $(DefineConstants);NO_GLOBALIZATION 15 | true 16 | true 17 | true 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /WebApi/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true, 5 | "iisExpress": { 6 | "applicationUrl": "http://localhost:59162", 7 | "sslPort": 44350 8 | } 9 | }, 10 | "profiles": { 11 | "http": { 12 | "commandName": "Project", 13 | "dotnetRunMessages": true, 14 | "launchBrowser": true, 15 | "applicationUrl": "http://localhost:5243", 16 | "environmentVariables": { 17 | "ASPNETCORE_ENVIRONMENT": "Development" 18 | } 19 | }, 20 | "https": { 21 | "commandName": "Project", 22 | "dotnetRunMessages": true, 23 | "launchBrowser": true, 24 | "applicationUrl": "https://localhost:7078;http://localhost:5243", 25 | "environmentVariables": { 26 | "ASPNETCORE_ENVIRONMENT": "Development" 27 | } 28 | }, 29 | "IIS Express": { 30 | "commandName": "IISExpress", 31 | "launchBrowser": true, 32 | "environmentVariables": { 33 | "ASPNETCORE_ENVIRONMENT": "Development" 34 | } 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /WebApiChiseled/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true, 5 | "iisExpress": { 6 | "applicationUrl": "http://localhost:59162", 7 | "sslPort": 44350 8 | } 9 | }, 10 | "profiles": { 11 | "http": { 12 | "commandName": "Project", 13 | "dotnetRunMessages": true, 14 | "launchBrowser": true, 15 | "applicationUrl": "http://localhost:5243", 16 | "environmentVariables": { 17 | "ASPNETCORE_ENVIRONMENT": "Development" 18 | } 19 | }, 20 | "https": { 21 | "commandName": "Project", 22 | "dotnetRunMessages": true, 23 | "launchBrowser": true, 24 | "applicationUrl": "https://localhost:7078;http://localhost:5243", 25 | "environmentVariables": { 26 | "ASPNETCORE_ENVIRONMENT": "Development" 27 | } 28 | }, 29 | "IIS Express": { 30 | "commandName": "IISExpress", 31 | "launchBrowser": true, 32 | "environmentVariables": { 33 | "ASPNETCORE_ENVIRONMENT": "Development" 34 | } 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /GrpcApi/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/dotnet/sdk:9.0-alpine AS build 2 | WORKDIR /app 3 | # these RUN lines below is optimization for current experiment to account for the fact that I have multiple similar configuration 4 | # best practices of Docker building imply that I put all dependencies in single line 5 | RUN apk add clang binutils musl-dev build-base zlib-static 6 | RUN apk add cmake 7 | RUN apk add openssl-dev openssl-libs-static openssl 8 | #RUN apk add protoc 9 | RUN wget -q -O /etc/apk/keys/sgerrand.rsa.pub https://alpine-pkgs.sgerrand.com/sgerrand.rsa.pub 10 | RUN wget https://github.com/sgerrand/alpine-pkg-glibc/releases/download/2.34-r0/glibc-2.34-r0.apk 11 | RUN apk add --force-overwrite glibc-2.34-r0.apk 12 | 13 | COPY nuget.config . 14 | COPY GrpcApi.csproj . 15 | RUN dotnet restore --runtime linux-musl-x64 GrpcApi.csproj 16 | 17 | COPY . . 18 | RUN dotnet publish -c Release -r linux-musl-x64 -o out GrpcApi.csproj 19 | 20 | FROM scratch AS runtime 21 | WORKDIR /app 22 | COPY --from=build /app/out/GrpcApi /app/ 23 | COPY --from=build /etc/ssl/certs/* /etc/ssl/certs/ 24 | ENV ASPNETCORE_URLS="https://+;http://+" 25 | EXPOSE 443 26 | EXPOSE 80 27 | ENTRYPOINT ["/app/GrpcApi"] 28 | -------------------------------------------------------------------------------- /CompressionEmbedding/Program.cs: -------------------------------------------------------------------------------- 1 | using System.IO.Compression; 2 | 3 | // Testing System.IO.Compression native libraries. 4 | TestGzip(); 5 | TestBrotli(); 6 | TestDeflate(); 7 | 8 | static void TestGzip() 9 | { 10 | var sourceStream = new MemoryStream(); 11 | using (var stringWriter = new StreamWriter(sourceStream, leaveOpen: true)) 12 | { 13 | stringWriter.WriteLine("This is text"); 14 | } 15 | 16 | sourceStream.Position = 0; 17 | 18 | var destinationStream = new MemoryStream(); 19 | using var compressor = new GZipStream(destinationStream, CompressionMode.Compress); 20 | sourceStream.CopyTo(compressor); 21 | destinationStream.Position = 0; 22 | 23 | Console.WriteLine($"Length of gzip archive is {destinationStream.Length}"); 24 | } 25 | 26 | static void TestBrotli() 27 | { 28 | var sourceStream = new MemoryStream(); 29 | using (var stringWriter = new StreamWriter(sourceStream, leaveOpen: true)) 30 | { 31 | stringWriter.WriteLine("This is text"); 32 | } 33 | 34 | sourceStream.Position = 0; 35 | 36 | var destinationStream = new MemoryStream(); 37 | using (var compressor = new BrotliStream(destinationStream, CompressionMode.Compress, leaveOpen: true)) 38 | { 39 | sourceStream.CopyTo(compressor); 40 | } 41 | 42 | destinationStream.Position = 0; 43 | 44 | Console.WriteLine($"Length of brotli archive is {destinationStream.Length}"); 45 | } 46 | 47 | static void TestDeflate() 48 | { 49 | var sourceStream = new MemoryStream(); 50 | using (var stringWriter = new StreamWriter(sourceStream, leaveOpen: true)) 51 | { 52 | stringWriter.WriteLine("This is text"); 53 | } 54 | 55 | sourceStream.Position = 0; 56 | 57 | var destinationStream = new MemoryStream(); 58 | using (var compressor = new DeflateStream(destinationStream, CompressionMode.Compress, leaveOpen: true)) 59 | { 60 | sourceStream.CopyTo(compressor); 61 | } 62 | 63 | destinationStream.Position = 0; 64 | 65 | Console.WriteLine($"Length of deflate archive is {destinationStream.Length}"); 66 | } 67 | -------------------------------------------------------------------------------- /NativeAOTDocker.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.5.002.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CompressionEmbedding", "CompressionEmbedding\CompressionEmbedding.csproj", "{B7F28D17-41CD-4A1A-95DF-9EDC29EF75BD}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EmbeddedICU", "EmbeddedICU\EmbeddedICU.csproj", "{9609965F-ED5C-4555-B3FB-1AF1321FA688}" 9 | EndProject 10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GrpcApi", "GrpcApi\GrpcApi.csproj", "{1BCB2BAA-32A3-4F5F-AB97-6C280BA16739}" 11 | EndProject 12 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GrpcApiClient", "GrpcApiClient\GrpcApiClient.csproj", "{F38CEA85-91A7-4793-894E-12F906EF9088}" 13 | EndProject 14 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "InvariantGlobalization", "InvariantGlobalization\InvariantGlobalization.csproj", "{3D17D717-0CEC-4575-92C3-CF6AED45D939}" 15 | EndProject 16 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NpgCli", "NpgCli\NpgCli.csproj", "{4CF174F3-AE9D-428A-91CF-9709CA057D4D}" 17 | EndProject 18 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NpgCliSlim", "NpgCliSlim\NpgCliSlim.csproj", "{25960806-4B63-440C-8F0E-5CD4132880C6}" 19 | EndProject 20 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenSslEmbedding", "OpenSslEmbedding\OpenSslEmbedding.csproj", "{A2CE7504-FB26-4BD9-BBC9-6B45F63498BF}" 21 | EndProject 22 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebApi", "WebApi\WebApi.csproj", "{D01B5453-645C-480D-8886-7FBD260D7E42}" 23 | EndProject 24 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebApiChiseled", "WebApiChiseled\WebApi.csproj", "{F19ED7B2-8F75-4DA9-A79A-C3DCAB27985D}" 25 | EndProject 26 | Global 27 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 28 | Debug|Any CPU = Debug|Any CPU 29 | Release|Any CPU = Release|Any CPU 30 | EndGlobalSection 31 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 32 | {B7F28D17-41CD-4A1A-95DF-9EDC29EF75BD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 33 | {B7F28D17-41CD-4A1A-95DF-9EDC29EF75BD}.Debug|Any CPU.Build.0 = Debug|Any CPU 34 | {B7F28D17-41CD-4A1A-95DF-9EDC29EF75BD}.Release|Any CPU.ActiveCfg = Release|Any CPU 35 | {B7F28D17-41CD-4A1A-95DF-9EDC29EF75BD}.Release|Any CPU.Build.0 = Release|Any CPU 36 | {9609965F-ED5C-4555-B3FB-1AF1321FA688}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 37 | {9609965F-ED5C-4555-B3FB-1AF1321FA688}.Debug|Any CPU.Build.0 = Debug|Any CPU 38 | {9609965F-ED5C-4555-B3FB-1AF1321FA688}.Release|Any CPU.ActiveCfg = Release|Any CPU 39 | {9609965F-ED5C-4555-B3FB-1AF1321FA688}.Release|Any CPU.Build.0 = Release|Any CPU 40 | {1BCB2BAA-32A3-4F5F-AB97-6C280BA16739}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 41 | {1BCB2BAA-32A3-4F5F-AB97-6C280BA16739}.Debug|Any CPU.Build.0 = Debug|Any CPU 42 | {1BCB2BAA-32A3-4F5F-AB97-6C280BA16739}.Release|Any CPU.ActiveCfg = Release|Any CPU 43 | {1BCB2BAA-32A3-4F5F-AB97-6C280BA16739}.Release|Any CPU.Build.0 = Release|Any CPU 44 | {F38CEA85-91A7-4793-894E-12F906EF9088}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 45 | {F38CEA85-91A7-4793-894E-12F906EF9088}.Debug|Any CPU.Build.0 = Debug|Any CPU 46 | {F38CEA85-91A7-4793-894E-12F906EF9088}.Release|Any CPU.ActiveCfg = Release|Any CPU 47 | {F38CEA85-91A7-4793-894E-12F906EF9088}.Release|Any CPU.Build.0 = Release|Any CPU 48 | {3D17D717-0CEC-4575-92C3-CF6AED45D939}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 49 | {3D17D717-0CEC-4575-92C3-CF6AED45D939}.Debug|Any CPU.Build.0 = Debug|Any CPU 50 | {3D17D717-0CEC-4575-92C3-CF6AED45D939}.Release|Any CPU.ActiveCfg = Release|Any CPU 51 | {3D17D717-0CEC-4575-92C3-CF6AED45D939}.Release|Any CPU.Build.0 = Release|Any CPU 52 | {4CF174F3-AE9D-428A-91CF-9709CA057D4D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 53 | {4CF174F3-AE9D-428A-91CF-9709CA057D4D}.Debug|Any CPU.Build.0 = Debug|Any CPU 54 | {4CF174F3-AE9D-428A-91CF-9709CA057D4D}.Release|Any CPU.ActiveCfg = Release|Any CPU 55 | {4CF174F3-AE9D-428A-91CF-9709CA057D4D}.Release|Any CPU.Build.0 = Release|Any CPU 56 | {25960806-4B63-440C-8F0E-5CD4132880C6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 57 | {25960806-4B63-440C-8F0E-5CD4132880C6}.Debug|Any CPU.Build.0 = Debug|Any CPU 58 | {25960806-4B63-440C-8F0E-5CD4132880C6}.Release|Any CPU.ActiveCfg = Release|Any CPU 59 | {25960806-4B63-440C-8F0E-5CD4132880C6}.Release|Any CPU.Build.0 = Release|Any CPU 60 | {A2CE7504-FB26-4BD9-BBC9-6B45F63498BF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 61 | {A2CE7504-FB26-4BD9-BBC9-6B45F63498BF}.Debug|Any CPU.Build.0 = Debug|Any CPU 62 | {A2CE7504-FB26-4BD9-BBC9-6B45F63498BF}.Release|Any CPU.ActiveCfg = Release|Any CPU 63 | {A2CE7504-FB26-4BD9-BBC9-6B45F63498BF}.Release|Any CPU.Build.0 = Release|Any CPU 64 | {D01B5453-645C-480D-8886-7FBD260D7E42}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 65 | {D01B5453-645C-480D-8886-7FBD260D7E42}.Debug|Any CPU.Build.0 = Debug|Any CPU 66 | {D01B5453-645C-480D-8886-7FBD260D7E42}.Release|Any CPU.ActiveCfg = Release|Any CPU 67 | {D01B5453-645C-480D-8886-7FBD260D7E42}.Release|Any CPU.Build.0 = Release|Any CPU 68 | {F19ED7B2-8F75-4DA9-A79A-C3DCAB27985D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 69 | {F19ED7B2-8F75-4DA9-A79A-C3DCAB27985D}.Debug|Any CPU.Build.0 = Debug|Any CPU 70 | {F19ED7B2-8F75-4DA9-A79A-C3DCAB27985D}.Release|Any CPU.ActiveCfg = Release|Any CPU 71 | {F19ED7B2-8F75-4DA9-A79A-C3DCAB27985D}.Release|Any CPU.Build.0 = Release|Any CPU 72 | EndGlobalSection 73 | GlobalSection(SolutionProperties) = preSolution 74 | HideSolutionNode = FALSE 75 | EndGlobalSection 76 | GlobalSection(ExtensibilityGlobals) = postSolution 77 | SolutionGuid = {8218E612-1951-481A-8E86-004F87000A74} 78 | EndGlobalSection 79 | EndGlobal 80 | -------------------------------------------------------------------------------- /calc.fsx: -------------------------------------------------------------------------------- 1 | #r "nuget: MathNet.Numerics, 5.0.0" 2 | #r "nuget: MathNet.Numerics.FSharp, 5.0.0" 3 | 4 | // Illustrates solving systems of simultaneous linear 5 | // equations using the DenseMatrix and LUDecomposition classes 6 | // in the Numerics.NET.LinearAlgebra namespace of Numerics.NET. 7 | 8 | #light 9 | 10 | open System 11 | 12 | open MathNet.Numerics 13 | // The DenseMatrix and LUDecomposition classes reside in the 14 | // Numerics.NET.LinearAlgebra namespace. 15 | open MathNet.Numerics.LinearAlgebra 16 | 17 | // The license is verified at runtime. We're using a 30 day trial key here. 18 | // For more information, see: 19 | // https://numerics.net/trial-key 20 | //let licensed = Numerics.NET.License.Verify("64542-18980-57619-62268") 21 | 22 | // A system of simultaneous linear equations is 23 | // defined by a square matrix A and a right-hand 24 | // side B, which can be a vector or a matrix. 25 | // 26 | // You can use any matrix type for the matrix A. 27 | // The optimal algorithm is automatically selected. 28 | 29 | [] 30 | let ConsoleInvariantGlobalization = 0 31 | [] 32 | let ConsoleWithICU = 1 33 | [] 34 | let ConsoleWithCompression = 2 35 | [] 36 | let AppHttpClient = 3 37 | [] 38 | let AppHttpClientWithSSL = 4 39 | [] 40 | let AppWebApi = 5 41 | [] 42 | let AppGrpcApi = 6 43 | [] 44 | let AppNpgSqlAdoIcu = 7 45 | [] 46 | let AppNpgSqlAdo = 8 47 | [] 48 | let AppOpenSSLFiles = 9 49 | [] 50 | let AppICU = 10 51 | [] 52 | let AppNpgSqlSlimBuilderIcu = 11 53 | [] 54 | let AppNpgSqlSlimBuilder = 12 55 | 56 | [] 57 | let ComponentRuntime = 0 58 | [] 59 | let ComponentGlobalizationSupport = 1 60 | [] 61 | let ComponentCompressionSupport = 2 62 | [] 63 | let ComponentHttpClient = 3 64 | [] 65 | let ComponentOpenSSLSupport = 4 66 | [] 67 | let ComponentWebApi = 5 68 | [] 69 | let ComponentGrpc = 6 70 | [] 71 | let ComponentNpgsqlAdoNet = 7 72 | [] 73 | let ComponentOpenSSLCertificates = 8 74 | [] 75 | let ComponentICUDatafiles = 9 76 | [] 77 | let ComponentNpgsqlBuilderSlim = 10 78 | 79 | let m = Matrix.Build.Dense(13, 11) 80 | // Console + Invariant globalization 81 | m[ConsoleInvariantGlobalization, ComponentRuntime] <- 1.0 82 | // Console + ICU 83 | m[ConsoleWithICU,ComponentRuntime] <- 1.0 84 | m[ConsoleWithICU,ComponentGlobalizationSupport] <- 1.0 85 | m[ConsoleWithICU,ComponentICUDatafiles] <- 1.0 86 | // Console + Brotli + Deflate + Gzip 87 | m[ConsoleWithCompression,ComponentRuntime] <- 1.0 88 | m[ConsoleWithCompression,ComponentCompressionSupport] <- 1.0 89 | // HttpClient 90 | m[AppHttpClient,ComponentRuntime] <- 1.0 91 | m[AppHttpClient,ComponentHttpClient] <- 1.0 92 | // HttpClient + OpenSSL 93 | m[AppHttpClientWithSSL,ComponentRuntime] <- 1.0 94 | m[AppHttpClientWithSSL,ComponentHttpClient] <- 1.0 95 | m[AppHttpClientWithSSL,ComponentOpenSSLSupport] <- 1.0 96 | m[AppHttpClientWithSSL,ComponentOpenSSLCertificates] <- 1.0 97 | // Web API 98 | m[AppWebApi,ComponentRuntime] <- 1.0 99 | m[AppWebApi,ComponentWebApi] <- 1.0 100 | // Grpc API 101 | m[AppGrpcApi,ComponentRuntime] <- 1.0 102 | m[AppGrpcApi,ComponentGrpc] <- 1.0 103 | // Npgsql ADO.NET + ICU 104 | m[AppNpgSqlAdoIcu,ComponentRuntime] <- 1.0 105 | m[AppNpgSqlAdoIcu,ComponentNpgsqlAdoNet] <- 1.0 106 | m[AppNpgSqlAdoIcu,ComponentGlobalizationSupport] <- 1.0 107 | m[AppNpgSqlAdoIcu,ComponentICUDatafiles] <- 1.0 108 | // Npgsql ADO.NET + Invariant globalization 109 | m[AppNpgSqlAdo,ComponentRuntime] <- 1.0 110 | m[AppNpgSqlAdo,ComponentNpgsqlAdoNet] <- 1.0 111 | // OpenSSL certificates 112 | m[AppOpenSSLFiles,ComponentOpenSSLCertificates] <- 1.0 113 | // Npgsql ADO.NET + Invariant globalization 114 | m[AppICU,ComponentICUDatafiles] <- 1.0 115 | // Npgsql ADO.NET + ICU 116 | m[AppNpgSqlSlimBuilderIcu,ComponentRuntime] <- 1.0 117 | m[AppNpgSqlSlimBuilderIcu,ComponentNpgsqlBuilderSlim] <- 1.0 118 | m[AppNpgSqlSlimBuilderIcu,ComponentGlobalizationSupport] <- 1.0 119 | m[AppNpgSqlSlimBuilderIcu,ComponentICUDatafiles] <- 1.0 120 | // Npgsql ADO.NET + Invariant globalization 121 | m[AppNpgSqlSlimBuilder,ComponentRuntime] <- 1.0 122 | m[AppNpgSqlSlimBuilder,ComponentNpgsqlBuilderSlim] <- 1.0 123 | 124 | // Console + ICU 125 | let b1 = vector[ 126 | 1.29; // Console + Invariant globalization (nativeaot-scratch-invariant) 127 | 35.14; // Console + ICU 128 | 2.22; // Console + Brotli + Deflate + Gzip (nativeaot-scratch-compression) 129 | 7.26; // HttpClient (nativeaot-scratch-http-client) 130 | 12.16; // HttpClient + OpenSSL (nativeaot-scratch-openssl) 131 | 21.94; // Web API (nativeaot-scratch-webapi) 132 | 23.46; // Grpc API (nativeaot-scratch-grpcapi) 133 | 50.98; // Npgsql ADO.NET + ICU (nativeaot-scratch-npgsql) 134 | 17.08; // Npgsql ADO.NET + Invariant globalization (nativeaot-scratch-npgsql-noicu) 135 | 0.; // OpenSSL certificates 136 | 0.; // ICU data 137 | 44.1; // NpgsqlSlimDataSourceBuilder + ICU (nativeaot-scratch-npgsql) 138 | 10.2; // NpgsqlSlimDataSourceBuilder + Invariant globalization (nativeaot-scratch-npgsql-noicu) 139 | ] 140 | 141 | Vector.Build.Dense(11) 142 | // Static immutable data 143 | b1[AppOpenSSLFiles] <- 0.64 144 | b1[AppICU] <- 29.4 145 | 146 | // 147 | // The Solve method 148 | // 149 | 150 | // The following solves m x = b1. The second 151 | // parameter specifies whether to overwrite the 152 | // right-hand side with the result. 153 | let x1 = m.Solve(b1) 154 | printfn "| Component | Size |" 155 | printfn "| ------------ | ----- |" 156 | printfn "| Barebone runtime + console | %.2fMB |" x1[ComponentRuntime] 157 | printfn "| ICU data | %.2fMB | " x1[ComponentICUDatafiles] 158 | printfn "| Globalization support | %.2fMB |" x1[ComponentGlobalizationSupport] 159 | printfn "| Brotli + Deflate + Gzip | %.2fMB |" x1[ComponentCompressionSupport] 160 | printfn "| HttpClient | %.2fMB |" x1[ComponentHttpClient] 161 | printfn "| OpenSSL | %.2fMB |" x1[ComponentOpenSSLSupport] 162 | printfn "| OpenSSL certificates | %.2fMB |" x1[ComponentOpenSSLCertificates] 163 | printfn "| Web API | %.2fMB |" x1[ComponentWebApi] 164 | printfn "| Grpc API | %.2fMB |" x1[ComponentGrpc] 165 | printfn "| Npgsql ADO.NET | %.2fMB |" x1[ComponentNpgsqlAdoNet] 166 | printfn "| Npgsql Builder Slim | %.2fMB |" x1[ComponentNpgsqlBuilderSlim] -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Scratch docker image using C# 2 | ============================= 3 | 4 | This repository is sample how to statically link console application into single executable and run on Docker. 5 | 6 | # Results 7 | 8 | This is sizes for experiment 9 | 10 | | Experiment | Size | Embed ICU | Embed OpenSSL | 11 | | ------------ | ----- | --- | ---------- | 12 | | Console + Invariant globalization | 1.29 MB | No | No | 13 | | Console + ICU | 35.14 MB | Yes | No | 14 | | Console + Brotli + Deflate + Gzip | 2.22 MB | No | No | 15 | | HttpClient | 7.26 MB | No | No | 16 | | HttpClient + OpenSSL | 12.16 MB | No | Yes | 17 | | Web API | 21.94 MB | No | Yes | 18 | | Grpc API | 23.46 MB | No | Yes | 19 | | Npgsql ADO.NET + ICU | 50.98 MB | Yes | Yes | 20 | | Npgsql ADO.NET + Invariant globalization | 17.08 MB | No | Yes | 21 | | Npgsql Builder Slim + ICU | 44.1 MB | Yes | Yes | 22 | | Npgsql Builder Slim + Invariant globalization | 10.2 MB | No | Yes | 23 | 24 | Chilsed for comparison 25 | 26 | | Experiment | Size | Embed ICU | Embed OpenSSL | 27 | | ------------ | ----- | --- | ---------- | 28 | | Web API | 30.46 MB | No | No | 29 | 30 | Resulting docker image have size of 1.56 MB. Thats after disabling reflection. That's the minimum which I can get without integrating with Docker tightly. Or is it kernel integration I'm dreaming about? Unikernels, I see unikernels around me 31 | 32 | # Sizes of the components 33 | 34 | Based on results I get approximate minimum size of code which added to your application if you using these libraries. 35 | 36 | | Component | Size | 37 | | ------------ | ----- | 38 | | Barebone runtime + console | 1.28MB | 39 | | ICU data | 29.40MB | 40 | | Globalization support | 4.47MB | 41 | | Brotli + Deflate + Gzip | 0.94MB | 42 | | HttpClient | 5.98MB | 43 | | OpenSSL | 4.26MB | 44 | | OpenSSL certificates | 0.64MB | 45 | | Web API | 20.66MB | 46 | | Grpc API | 22.18MB | 47 | | Npgsql ADO.NET | 15.82MB | 48 | | Npgsql Builder Slim | 8.93MB | 49 | 50 | # Build and Run 51 | 52 | ## Embedded ICU - 35.14 MB 53 | ```shell 54 | docker build -t nativeaot-scratch EmbeddedICU 55 | docker run -i nativeaot-scratch 56 | ``` 57 | 58 | 30 MB is ICU data. 59 | 60 | ## Invariant globalization - 1.29 MB 61 | ```shell 62 | docker build -t nativeaot-scratch-invariant InvariantGlobalization 63 | docker run -i nativeaot-scratch-invariant 64 | ``` 65 | 66 | ## Brotli + Deflate + Gzip - 2.22 MB 67 | ```shell 68 | docker build -t nativeaot-scratch-compression CompressionEmbedding 69 | docker run -i nativeaot-scratch-compression 70 | ``` 71 | 72 | ## HttpClient - 7.26 MB 73 | with reflection unfortunately 74 | ```shell 75 | docker build -t nativeaot-scratch-http-client -f OpenSslEmbedding/Dockerfile.nossl OpenSslEmbedding 76 | docker run -i nativeaot-scratch-http-client 77 | ``` 78 | 79 | ## HttpClient + OpenSSL - 12.16 MB 80 | with reflection unfortunately 81 | ```shell 82 | docker build -t nativeaot-scratch-openssl OpenSslEmbedding 83 | docker run -i nativeaot-scratch-openssl 84 | ``` 85 | 86 | ## Web API - 21.94 MB 87 | with reflection unfortunately 88 | ```shell 89 | docker build -t nativeaot-scratch-webapi WebApi 90 | docker run -p 5022:80 -i nativeaot-scratch-webapi 91 | ``` 92 | 93 | Web API accessible on http://localhost:5022. 94 | 95 | For SSL configuration take a look at https://learn.microsoft.com/en-us/dotnet/core/additional-tools/self-signed-certificates-guide#with-openssl nd create `certs` folder with certificates. Then you can run following command. 96 | 97 | ``` 98 | docker run --rm -it -p 8000:80 -p 8001:443 -e ASPNETCORE_URLS="https://+;http://+" -e ASPNETCORE_HTTPS_PORT=8001 -e ASPNETCORE_ENVIRONMENT=Development -e ASPNETCORE_Kestrel__Certificates__Default__Path=/https/contoso.com.crt -e ASPNETCORE_Kestrel__Certificates__Default__KeyPath=/https/contoso.com.key -v $PWD\certs/:/https/ nativeaot-scratch-webapi 99 | ``` 100 | 101 | Web API accessible on http://localhost:8000 and https://localhost:8001. 102 | 103 | ## GrpcApi - 23.46 MB 104 | with reflection unfortunately 105 | ```shell 106 | docker build -t nativeaot-scratch-grpcapi GrpcApi 107 | docker run --rm -it -p 8010:80 -p 8011:443 -e ASPNETCORE_URLS="https://+;http://+" -e ASPNETCORE_HTTPS_PORT=8001 -e ASPNETCORE_ENVIRONMENT=Development -e ASPNETCORE_Kestrel__Certificates__Default__Path=/https/contoso.com.crt -e ASPNETCORE_Kestrel__Certificates__Default__KeyPath=/https/contoso.com.key -v $PWD\certs/:/https/ nativeaot-scratch-grpcapi 108 | ``` 109 | 110 | ## NpgCli + Globalization - 50.98 MB 111 | with reflection unfortunately 112 | ```shell 113 | docker build -t nativeaot-scratch-npgsql NpgCli 114 | docker run -i -e ConnectionString='Host=172.17.0.2;Username=postgres;Password=postgrespw' nativeaot-scratch-npgsql 115 | ``` 116 | 117 | ## NpgCli - 17.08 MB 118 | with reflection unfortunately 119 | ```shell 120 | docker build -t nativeaot-scratch-npgsql-noicu NpgCli -f NpgCli/Dockerfile.noicu 121 | docker run -i -e ConnectionString='Host=172.17.0.2;Username=postgres;Password=postgrespw' nativeaot-scratch-npgsql-noicu 122 | ``` 123 | 124 | ## Web API on Chiseled - 30.46 MB 125 | with reflection unfortunately 126 | ```shell 127 | docker build -t nativeaot-scratch-webapi-chiseled WebApiChiseled 128 | docker run -p 5122:80 -i nativeaot-scratch-webapi-chiseled 129 | ``` 130 | 131 | Web API accessible on http://localhost:5122. 132 | 133 | docker run --rm -it -p 8000:80 -p 8001:443 -e ASPNETCORE_URLS="https://+;http://+" -e ASPNETCORE_HTTPS_PORT=8001 -e ASPNETCORE_ENVIRONMENT=Development -e ASPNETCORE_Kestrel__Certificates__Default__Path=/https/contoso.com.crt -e ASPNETCORE_Kestrel__Certificates__Default__KeyPath=/https/contoso.com.key -v $PWD\certs/:/https/ nativeaot-scratch-webapi 134 | 135 | 136 | # Inspeciting scratch container 137 | 138 | You can use dive 139 | ```shell 140 | docker run --rm -it ` 141 | -v /var/run/docker.sock:/var/run/docker.sock ` 142 | wagoodman/dive:latest nativeaot-scratch 143 | ``` 144 | 145 | or export tar with container 146 | 147 | ``` 148 | docker save nativeaot-scratch -o nativeaot-scratch.tar 149 | ``` 150 | 151 | # Testing that building inside Alpine works. 152 | 153 | That's was needed when NativeAOT does not have objwriter for musl. Still interesting if you need to build augment ObjWriter. 154 | ``` 155 | docker build -t test-build -f Dockerfile.objwriter . 156 | ``` 157 | 158 | # Smoke test for ObjWriter build 159 | 160 | ``` 161 | docker build -t nativeaot-scratch-build -f Dockerfile.objwriter . 162 | docker run -i nativeaot-scratch-build 163 | ``` 164 | 165 | Compiled `libobjwriter.so` is located at `artifacts/obj/InstallRoot-/lib` inside docker. 166 | 167 | 168 | ``` 169 | docker run --name postgres-aot -e "POSTGRES_USER=postgres" -e "POSTGRES_PASSWORD=postgrespw" -p 5432:32768 -d postgres 170 | ``` --------------------------------------------------------------------------------