Releases: SimplifyNet/Simplify.Web
Release list
5.5
Added
- MaxRequestBodySize setting (default: 100 MB) to cap request body reads during
model binding, preventing memory-exhaustion DoS. Configurable via
SimplifyWebSettings:MaxRequestBodySizein appsettings.json.
Security
- Http500ErrorPageBuilder: HTML-encode exception text before rendering it in the
error page, closing an XSS vector when HideExceptionDetails is false.
Fixed
- StringToSpecifiedObjectParser: wrap Enum.Parse in a try/catch with a clear
ModelBindingException message and pass ignoreCase: true so route parameter casing
does not cause spurious binding failures. - File response: use
await usingfor the data stream so it is disposed correctly
under all target frameworks. - SimplifyWebRequestMiddleware: preserve the original exception when the OnException
handler itself throws, instead of replacing it with the handler's exception. - RequestPathExtensions: normalize multiple leading slashes in the request path
to prevent path-traversal probes via "//" prefixed URLs. - AuthorizeAttribute: treat empty or whitespace-only role strings as absent so that
[Authorize("")]does not bypass authorization entirely. - JsonModelBinder: use StartsWith (ordinal, ignore-case) instead of Contains for the
Content-Type check to avoid matching unrelated media types.
Changed
- StaticFile: add CopyToAsync(Stream, string) that streams file content directly to
the target stream without loading it into memory first. NewFileHandler now uses
this streaming path, reducing memory pressure for large static files. - InMemoryFilesCacheHandler: use TryAdd instead of the indexer to avoid a race
condition when multiple threads cache the same file concurrently.
5.4
Added
- HTTP QUERY method support via HttpMethod.Query and the [Query] controller route attribute.
Security
- Redirector: reject relative redirect URLs containing control characters (e.g. tab) in
IsSameSiteUrl, closing a bypass where browsers strip such characters when resolving a
Location header, turning "/\t/evil.com" into a protocol-relative "//evil.com".
Fixed
- MaxAttribute / MinAttribute / RangeAttribute: only throw the custom/string-table error
message after the bounds check actually fails, instead of unconditionally whenever a
custom message was configured. - ValidationAttributesExecutor: IsGenericList now detects closed generic lists (e.g.
List), not just IList itself, avoiding a TargetParameterCountException when
validating models with populated List properties. - HeaderTimeExtensions: use DateTime.TryParseExact instead of ParseExact for the
If-Modified-Since header so a malformed value is treated as absent instead of throwing
an unhandled FormatException on static file requests. - Controller2Executor: fall back to an empty route parameter set instead of a
null-forgiving RouteParameters, turning a NullReferenceException into a clear
InvalidOperationException for parameterized V2 controllers used as Global/Forbidden/NotFound
handlers. - StringToSpecifiedObjectParser: parse int/long/decimal/DateTime with
CultureInfo.InvariantCulture to prevent silent data corruption under non-invariant server
cultures (e.g. "1.234" misread as 1234 under de-DE). - ListToModelParser: use ToLowerInvariant instead of ToLower for property/key matching to
avoid the Turkish-I bug breaking form/query binding under tr-TR/az server culture. - StringTable: replace the plain Dictionary-backed cache with ConcurrentDictionary to
eliminate a read-while-write race when StringTableMemoryCache is enabled.
5.3
Added
- File Response with Stream (#327)
- Explicit .NET 10 Support
Removed
- Explicit .NET 6 Support
Fixed
- StatusCode cannot be set because the response has already started (#288)
- Skip error page write when response has already started in SimplifyWebRequestMiddleware
Changed
- Handle partial reads in StaticFile.GetDataAsync and add NET7_0_OR_GREATER branch using ReadExactlyAsync
Dependencies
- Microsoft.Extensions.Configuration.Binder bump to 10.0.9
- Microsoft.Extensions.Configuration.Json bump to 10.0.9
- Simplify.DI bump to 4.3
- Simplify.Templates to 2.0.3
- Simplify.System bump to 1.6.3
- Simplify.String.Sources internal bump to 1.2.3
- Simplify.Xml.Sources internal bump to 1.4.1
5.2
Security
-
StaticFiles: prevent path traversal by normalizing the resolved path with
Path.GetFullPath, rejecting '..' / NUL sequences, and verifying containment
inside the configured site root (case-insensitive on Windows/macOS).
Both IsValidPath() and the data-reading methods now use the safe resolver. -
FilesInMemoryCache / InMemoryFilesCacheHandler: bound the in-memory cache
(MaxItems, default 1024), normalize keys case-insensitively to defeat
path case-variant OOM DoS, and invalidate stale entries based on the
file's last-modification timestamp. -
Redirector: harden Redirect(string) - accept same-origin relative paths
only when they start with '/' (rejecting '//' and '/' scheme-spoofs)
and compare absolute URLs by scheme+host+port instead of substring
StartsWith. All redirect/login/previous-page cookies are now HttpOnly,
SameSite=Lax, Secure. -
SimplifyWebSettings: default HideExceptionDetails to true so unhandled
exception stack traces are no longer leaked to anonymous users by default. -
LanguageManager: language cookie switched from SameSite=None to Lax.
Fixed
-
WebContext: pass leaveOpen:true to the StreamReader used to consume the
request body so subsequent middleware/model binders can still read it;
add double-check inside semaphore-guarded sections; implement IDisposable
so per-scope semaphores release their kernel handles. -
ControllerMetadata: detect [Authorize] on base controllers (inherit:true)
so derived controllers don't silently become anonymous. -
AuthRedirectExtensions: only issue the 401->redirect when the response
has not started, avoiding InvalidOperationException 500s when upstream
authentication middleware already flushed a challenge. -
FileReader: replace static Dictionary caches guarded by an external lock
with ConcurrentDictionary to eliminate read-while-write corruption. -
TemplateFactory: replace Dictionary + dual lock/semaphore primitives with
a ConcurrentDictionary cache and unify sync/async paths on a single
SemaphoreSlim to avoid duplicate-add races.
Dependencies
- Microsoft.Extensions.Configuration.Binder bump to 8.0.2
- Simplify.DI bump to 4.2.11
5.1
5.0
Breaking
- Internal framework restructure and rewrite (http request and response handling related functionality and metadata rewritten from scratch). Can affect any customizations to related functionality
Added
- Version 2 controllers
- Built-in Json response using System.Text.Json
- Built-in JSON model binder (enabled by default)
- Switchable measurements (StopwatchProvider), disabled by default
Removed
- .NET Framework 4.8 explicit support
UseSimplifyWebWithoutRegistrationsandUseSimplifyWebNonTerminalWithoutRegistrationsIApplicationBuildermethodsISimplifyWebSettingsoverride viaRegisterSimplifyWebSettingsIConfigurationoverride viaOverrideConfigurationorRegisterConfiguration- 400 special controller attribute
Changed
UseSimplifyWebandUseSimplifyWebNoNTerminalnow require passingtrueto automatically register it's own bootstrapper registrationsRegisterSimplifyWebnow extension method ofIDIRegistratorinstead ofIDIContainerProvider, custom internalIDIContainerProvidercan be passed via method parameter, if required- Internal
IConfigurationregistration override viaRegisterSimplifyWeb - Static files disabled by default (when disabled, static files IOC container registrations will be skipped)
Environmentsplit toEnvironmentandDynamicEnvironment- V1 controllers RouteParameters defaulted to empty ExpandoObject to avoid NRE
SimplifyWebSettingsloading thru binder- Controllers search on execution optimized
- XML comments revisited/updated
Fixed
- Multiple one route controllers handling
- Multiple middlewares having same
IsTerminalstatus
Dependencies
- Switched to explicit Simplify.System 1.6.2 instead of internal Simplify.System.Sources
- Microsoft.Extensions.Configuration.Json bump to 8.0.0
- Microsoft.Extensions.Configuration.Binder 8.0.1 added
- Simplify.Templates bump to 2.0.2
- Internal Simplify.Xml.Sources bump to 1.4
5.0-pre01
Breaking
- Internal framework restructure and rewrite (http request and response handling related functionality and metadata rewritten from scratch). Can affect any customizations to related functionality
Added
- Version 2 controllers
- Built-in Json response using System.Text.Json
- Built-in JSON model binder (enabled by default)
- Switchable measurements (StopwatchProvider), disabled by default
Removed
- .NET Framework 4.8 explicit support
UseSimplifyWebWithoutRegistrationsandUseSimplifyWebNonTerminalWithoutRegistrationsIApplicationBuildermethodsISimplifyWebSettingsoverride viaRegisterSimplifyWebSettingsIConfigurationoverride viaOverrideConfigurationorRegisterConfiguration- 400 special controller attribute
Changed
UseSimplifyWebandUseSimplifyWebNoNTerminalnow require passingtrueto automatically register it's own bootstrapper registrationsRegisterSimplifyWebnow extension method ofIDIRegistratorinstead ofIDIContainerProvider, custom internalIDIContainerProvidercan be passed via method parameter, if required- Internal
IConfigurationregistration override viaRegisterSimplifyWeb - Static files disabled by default (when disabled, static files IOC container registrations will be skipped)
Environmentsplit toEnvironmentandDynamicEnvironment- V1 controllers RouteParameters defaulted to empty ExpandoObject to avoid NRE
SimplifyWebSettingsloading thru binder- Controllers search on execution optimized
- XML comments revisited/updated
Fixed
- Multiple one route controllers handling
- Multiple middlewares having same
IsTerminalstatus
Dependencies
- Switched to explicit Simplify.System 1.6.2 instead of internal Simplify.System.Sources
- Microsoft.Extensions.Configuration.Json bump to 8.0.0
- Microsoft.Extensions.Configuration.Binder 8.0.1 added
- Simplify.Templates bump to 2.0.2
- Internal Simplify.Xml.Sources bump to 1.4
4.9
4.8.1
4.8
Changed
- !Important! Setting language from cookie on requests disabled by default, to enable set
AcceptCookieLanguagesetting totrueinSimplifyWebSettings(#246) AcceptBrowserLanguagesetting renamed toAcceptHeaderLanguage(#246)- The way framework checks that applying language is valid
Fixed
- Invariant language setting and check
Added
- Set content type
text/plainfor all string responses by default (#247) AcceptCookieLanguagesetting