Blog
Mert Özen's blog posts on software development, backend, frontend, and DevOps.
The LLM Context Window: What the Model Remembers and What It Silently Cuts
LLM APIs are stateless; you send the chat history with every request and every turn grows the bill. Even though Gemma 3 supports 128K tokens, Ollama allocates a 4096-token window by default and cuts a 4498-token prompt down to 2051 tokens without any error. We set num_ctx in C# and TypeScript and try managing history with trimming and summarizing, using real output.
Your First LLM Request: The First Answer with Ollama, C# and TypeScript
We get to know Ollama, look at models with ollama list and ollama ps, and send the first request to the /api/chat endpoint with curl. Then we repeat it in C# with Microsoft.Extensions.AI and OllamaSharp and in TypeScript with the ollama package, and use real output to read the token counts, the nanosecond durations and why the first request is slow.
OWASP Top 10: What Changed from 2021 to 2025 and Updating Old Documents
SSRF joining A01, the components problem growing into Software Supply Chain Failures, Security Misconfiguration rising to second place, the new A10 Mishandling of Exceptional Conditions and three renames. We read the 2025 methodology with its numbers and write a small .NET tool that finds old and year-less category numbers and suggests their 2025 counterparts.
OWASP A04: Cryptographic Failures (1) — Encoding, Hashing, Encryption and HTTPS
Why Base64 is not encryption and how hashing differs from encryption. We catch tampered data with AES-GCM, use RandomNumberGenerator instead of Random for password reset codes, see why MD5 is wrong for passwords, turn on the CA5351 and CA5394 analyzers, and inspect HTTPS redirection and HSTS defaults in ASP.NET Core with curl.
Dapper.AOT: Dapper with Source Generators, Interceptors and Native AOT
Why does vanilla Dapper blow up even under dotnet run once PublishAot is on? Generating the code at build time with Dapper.AOT 1.1.0: [module: DapperAot], InterceptorsNamespaces, the generated interceptor code, Native AOT publish and a startup time going from 49.8 ms to 4.3 ms, type handlers as attributes, the DAP analyzers and limitations such as QueryMultiple.
Dapper Performance: Query Cache, GetRowParser and Bulk Alternatives with SqlBulkCopy and COPY
What Dapper's query cache holds and why it draws a saw blade, when CommandFlags.NoCache is needed, choosing a type per row with GetRowParser, and for the bulk operations Dapper lacks: a transaction on SQLite, SqlBulkCopy on SQL Server and COPY on PostgreSQL, all with real measurements, closing with BenchmarkDotNet.
Dynamic SQL with Dapper: SqlBuilder, Safe Filters and Contrib, Dommel, Dapper Plus
Building optional filters without string concatenation: Dapper.SqlBuilder's templates and placeholders, count and page queries from one builder, safe sorting with a whitelist and the OrWhere surprise. Then a balanced look at Dapper.Contrib, Rainbow, Dommel and the commercial Dapper Plus as of November 2026.
Dapper and SQL Server: TVPs, ANSI Strings, {=literal} and Parameter Sniffing
Queries that return the right result but scan the whole index: the implicit conversion nvarchar parameters cause on varchar columns, Dapper's 4000-character rule, IN lists multiplying plans, table-valued parameters, filtered indexes with {=literal} and parameter sniffing, all with real logical-reads measurements.
Stored Procedures with Dapper: Output, Return Value and the Auto-Detection Trap of 2.1.11
SQLite has no stored procedures, so we move to SQL Server in docker: CommandType.StoredProcedure, output and return values with DynamicParameters, how SET NOCOUNT affects Execute, single-word commands mistaken for procedures since 2.1.11, and the function vs procedure difference in PostgreSQL.
Type Handlers and Custom Mapping in Dapper: Guid, DateTimeOffset and CustomPropertyTypeMap
Why does Dapper blow up when reading Guid, DateTimeOffset and TimeSpan on SQLite? We write interpreters with SqlMapper.TypeHandler<T>, see from the source why SetValue is never called, and cover the DateOnly/TimeOnly story of 2.1.86 and column mapping with CustomPropertyTypeMap.
Buffered and Unbuffered Reads in Dapper: Streaming Large Result Sets
We measure the difference between buffered and unbuffered reads in Dapper: an unbuffered result re-running the query on every enumeration, 191 MB versus near-zero memory on a million rows, IAsyncEnumerable streaming with QueryUnbufferedAsync, cancellation with WithCancellation and the disposed-connection trap, all with real output.
QueryMultiple and GridReader in Dapper: Several Result Sets in One Round Trip
We read several result sets from one command with Dapper's QueryMultiple and GridReader: why grids are read in order and only once, loading a master-detail order in one round trip, joining two result sets in memory, the unbuffered grid trap, and when to pick it over multi-mapping, all with real output.