Blog
Mert Özen's blog posts on software development, backend, frontend, and DevOps.
What's New in MVC and Razor Pages from .NET 8 to .NET 11
With .NET 8 and 9 support ending on November 10, 2026, the target for MVC and Razor Pages apps is .NET 10. Running one project on net8.0 and net10.0, we show cookie auth returning 401 instead of 302 for API endpoints, the Minimal API form binding change, the ASP0026 warning and RazorComponentResult, plus .NET 11's MVC items and an upgrade checklist.
Migrating from ASP.NET MVC 5 to ASP.NET Core MVC: Equivalents of Global.asax, Web.config, HtmlHelper and Bundling
Moving from MVC 5 to ASP.NET Core turns Global.asax into Program.cs, Web.config into Options, HttpModules into middleware, child actions into view components and bundling into MapStaticAssets; a large app moves piece by piece behind a YARP fallback. We show real build errors for @helper and @Html.Action, the CS0104 trap with System.Web adapters and what replaced Upgrade Assistant.
Razor Pages with htmx: Interactive UI Without an SPA, Partial Responses and Antiforgery
With htmx, Razor Pages handlers return the full page or just a partial depending on the HX-Request header; live search, infinite scroll and inline editing work without JSON or an SPA. We carry the antiforgery token with hx-headers and show the Vary and history restore pitfalls, htmx 2's 4xx behavior and htmx 4 differences with real requests.
Localization in MVC and Razor Pages: IStringLocalizer, IViewLocalizer, Request Culture and the Turkish "i" Pitfall
UseRequestLocalization picks a culture per request from the query string, cookie, Accept-Language or the URL; .resx files, IViewLocalizer and DataAnnotations messages are translated with it. We make Bookstore's catalog TR/EN and show the tr vs tr-TR gap, 25,5 becoming 255 in the query string, the "C" format and the Turkish i pitfall with real output.
Static Assets and UI Plumbing: MapStaticAssets, Fingerprinting, CSS Isolation and Client Libraries
MapStaticAssets discovers files at build time, compresses them with gzip/Brotli and gives fingerprinted URLs a one-year immutable cache. We measure it with real headers and show why MapControllerRoute(...).WithStaticAssets() in the .NET 10 MVC template does nothing and how to fix it, the tag helper trap in CSS isolation, and using LibMan.
Razor Pages: PageModel, Handler Methods, Page Routing and When to Use It Instead of MVC
With @page a Razor file becomes an endpoint, and PageModel handlers such as OnGetAsync and OnPostDeleteAsync replace actions. We rewrite Bookstore's admin CRUD and examine SupportsGet, TempData, AuthorizeFolder and page filters, why an unmatched handler ends in a 500, and the file layout versus MVC, with real output.
Server-Side and Client-Side Validation: DataAnnotations, ModelState, Unobtrusive Validation and Custom Attributes
Validation in MVC has two layers: DataAnnotations and ModelState are mandatory on the server, while jQuery Unobtrusive Validation driven by data-val-* is only user experience. We try IValidatableObject, AddModelError, [Remote], a custom attribute with IClientModelValidator and Turkish messages in a real browser, and show how under a Turkish culture a price of "1.5" is silently saved as 15 and how type="number" with __Invariant fixes it.
Forms in MVC and Razor Pages: Model Binding, Post-Redirect-Get, Antiforgery and Overposting
In MVC controllers the form tag helper produces an antiforgery token but nothing validates it: a tokenless curl request saved a book until AutoValidateAntiforgeryTokenAttribute turned it into a 400. With real requests we cover Post-Redirect-Get and TempData, sending the token in a fetch header, binding collections, nested objects, checkboxes and enums plus the index gap, overposting that set stock to 999 through an entity, and how [Bind] wipes data on updates.
ASP.NET Core Tag Helpers: Built-in Tag Helpers and Writing Your Own
A tag helper is a C# class, bound at compile time, that processes an HTML tag in Razor on the server; a single asp-for produces id, name, label, input type and data-val attributes. We look at the real output of the built-in anchor, form, input, select, environment and cache tag helpers, the difference from HTML Helpers and the build break from a missing @ on an enum attribute, then write our own <status-badge> and a permission-aware <secure-link>.
Partial Views, View Components and Razor Components: Reusing UI Pieces in MVC
Use a partial view for repeated HTML whose data the caller already has, a view component for a fragment on every page that fetches its own data, and a Razor component as a bridge to Blazor or for a piece that will become interactive. We measure queries jumping from 3 to 7 when a partial calls DbContext, build a cart summary view component, return ViewComponent() from a controller and try the <component> tag helper's Static and ServerPrerendered modes.
Razor Syntax and Layouts: @ Expressions, HTML Encoding, _Layout, Sections, _ViewStart and _ViewImports
Razor HTML-encodes every value written with @ by default; that shuts out XSS but also turns non-ASCII letters such as Turkish ı into entities like ı, fixed with WebEncoderOptions. With real output we cover implicit vs explicit expressions, the danger of Html.Raw and of embedding '@Model' in JavaScript, Json.Serialize, sections, the _ViewStart/_ViewImports hierarchy and the lost-section error in nested layouts.
The ASP.NET Core MVC Pattern in Practice: Controllers, Views, ViewModels and Conventional Routing
In ASP.NET Core MVC a controller derives from Controller, finds its view by name in Views/<Controller> and Shared, and gets page data through a type-safe ViewModel instead of ViewBag. On Bookstore we look at the dotnet new mvc layout, conventional routing, RedirectToAction, an Admin area and a real bug where swapping route order makes links silently point to the wrong address.