Oct 05

Stop System.Text.Json from accepting the same JSON property twice

Send the same property twice in one JSON body and System.Text.Json keeps the last copy, with a 200 and no warning. Anything that read the body first and kept a different copy is now acting on a different value. .NET 10 added AllowDuplicateProperties, which defaults to true, and one line turns the rejection on.

dotnet · security · 5 min
→
Oct 04

Angular's HttpClient only sends the XSRF header to its own origin

Angular copies the XSRF-TOKEN cookie into an X-XSRF-TOKEN header for every request to the page's own origin except GET and HEAD, and for nothing else. An app on app.example.com calling api.example.com sends no header at all, so the antiforgery check answers 400 — and renaming the cookie does not help.

angular · security · 6 min
→
Oct 01

What decides whether SearchValues<string> beats a Contains loop

A loop of Contains reads the text once per keyword; SearchValues<string> reads it once. At eight keywords that is a fifth of the time. At forty of the same kind of keyword the loop wins, because string.Contains is vectorised and what costs in the single pass is how often its SIMD prefilter stops to verify a candidate.

dotnet · performance · 8 min
→
Sep 30

Deterministic cleanup in TypeScript with await using and DisposableStack

using and await using close a resource when the block ends, whether it ends normally or by throwing, and they close several resources in reverse order of opening. Three nested try/finally blocks become three lines, DisposableStack covers the case where the count is only known at run time, and a cleanup that throws gives you a SuppressedError whose two fields are easy to read backwards.

typescript · patterns · 7 min
→
Sep 29

Replacing fakeAsync and tick when Angular tests move to Vitest

Angular projects generated today run their tests on Vitest with no zone.js at all, so fakeAsync and tick throw before the first assertion. The replacement is vi.useFakeTimers, and the part that costs an afternoon is that zoneless change detection schedules its own render on a timer, so fixture.whenStable() waits for a clock nobody is winding.

angular · testing · 7 min
→
Sep 28

Minimal API validation in .NET 10: what AddValidation checks and what it skips

One call, builder.Services.AddValidation(), finally makes a minimal API enforce the DataAnnotations attributes on its own parameters and answer a bad request with a 400 listing the fields. It also steps over an array property, a dictionary property, any parameter that bound to null, and every endpoint mapped from a class library.

dotnet · development · 8 min
→
Sep 27

ASP.NET Core does not block HTML in a form post, and Quill sends plenty

ASP.NET MVC 5 answered a form post containing markup with a 'potentially dangerous value' error, and a generation of .NET developers learned to expect the framework to be watching. ASP.NET Core dropped that check on purpose. The markup binds, gets stored, and comes back out on the next reader's page the moment a view renders it raw — unless something on the server cleans it against an allowlist first, which is a line you write yourself.

dotnet · security · 7 min
→
Sep 24

Server-side paging with Tabulator and ASP.NET Core MVC

In remote mode Tabulator asks an MVC controller for one page, expects data and last_page back, and reads last_row when it is there. Two things bite on the way: the bracketed query string it sends binds to an empty list under MVC's default value providers, and the column name it asks you to sort by is a string the browser chose.

dotnet · performance · 7 min
→
Sep 23

Give a Leaflet map its height before you create it

A Leaflet map reads its container's size when you create it and caches the answer. Create it into a box that has no height yet and it stays zero pixels tall, showing the grey that leaflet.css paints on an empty container. Under server-side rendering the usual advice makes it worse, because ngAfterViewInit runs in Node and afterNextRender does not.

angular · development · 6 min
→
Sep 22

Wire CodeMirror 6 into an Angular form without collapsing the caret

CodeMirror 6 keeps its own copy of the document and changes it through transactions, so wiring it up the way you wire an input either collapses the caret or recurses until the stack ends. The flow that works is one-way, and the line people forget is the one that shuts the view down: an EditorView registers handlers on the document, on the window and on every ancestor element up to html, and Angular removing the component takes back none of them.

angular · architecture · 5 min
→