With all this AI features available, you would expect that you no longer loose time on stupid issues. Unfortunately, we are not there yet. I lost a chunk of time today to a behavior in SQL Server that, once you know it, is totally obvious — but until then is absolutely maddening. I'm sharing it here so hopefully you don't lose the same time I did. The setup I had a script meant to be idempotent: create a database user if it doesn't exist, or update it if it does. Standard stuff. Here's a simplified version: Looks fine, right? Run it once — works. Run it a second time and SQL Server throws an error saying it can't find usr_SampleDB_reader . The user you just created. In the same database. With the same script. What's actually happening When you run ALTER USER [...] WITH LOGIN = [...] , SQL Server renames the user to match the login name — by default, silently, without a warning. So after the first run, usr_SampleDB_reader no longer exists. It's...
In the previous post, we looked at how to implement IValidateOptions<T> by hand — writing a dedicated validator class, injecting services, and expressing cross-property constraints that Data Annotations can't handle. That approach gives you full control and is the right tool when validation logic is genuinely complex. While researching that post I discovered another feature that's worth knowing about: when your validation can be expressed with Data Annotation attributes, the options validation source generator (available since .NET 8) will write the IValidateOptions<T> implementation for you at compile time. You get the safety of startup validation without the boilerplate, and as a bonus the generated code is reflection-free and AOT-compatible. The problem with runtime data annotations Before the source generator existed, the standard way to add annotation-based validation was ValidateDataAnnotations() : This works, but it uses reflection at runtime to ...