Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
4045315
✨ add TargetFrameworkMoniker class and API documentation
aicia-bot Jul 31, 2026
145f586
📦 add release notes for TargetFrameworkMoniker in v10.6.0
aicia-bot Jul 31, 2026
00c165d
🎨 remove legacy analyzer exclusions from editorconfig
aicia-bot Aug 1, 2026
0cce050
✨ introduce Cuemon.Extensions.FileProviders.Physical library
aicia-bot Aug 4, 2026
1ea6106
📦 publish Cuemon.Extensions.FileProviders.Physical package metadata
aicia-bot Aug 4, 2026
0a18ed7
⬆️ upgrade Codebelt and Microsoft.Extensions dependencies
aicia-bot Aug 4, 2026
f6bd5b5
✅ add AwaiterBenchmark
aicia-bot Aug 4, 2026
61932e0
📝 update test workflow documentation in AGENTS
aicia-bot Aug 5, 2026
4770d4f
🔧 add Cuemon.Extensions.FileProviders.Physical to DocFX
aicia-bot Aug 5, 2026
f20c35a
⚡ improve code quality across logging and TFM patterns
aicia-bot Aug 5, 2026
b7f1cf7
📝 modernize XML documentation references across source tree
aicia-bot Aug 5, 2026
736eedf
📖 update API documentation examples and add FileProviders namespace
aicia-bot Aug 5, 2026
001c2fa
📝 fix xml doc cref formatting for disposable methods
aicia-bot Aug 5, 2026
3620fba
🐛 add cancellation token support to awaiter retry loop
aicia-bot Aug 5, 2026
e215061
🚚 move awaiter benchmark to threading subfolder
aicia-bot Aug 5, 2026
ab2db3c
✨ add async run options with time provider and attempt limits
aicia-bot Aug 5, 2026
82905bb
🐛 update awaiter to use new options features
aicia-bot Aug 5, 2026
016e89d
✅ add tests for async run options enhancements
aicia-bot Aug 5, 2026
2b557ae
📝 update documentation for async run and awaiter
aicia-bot Aug 5, 2026
8819b30
➕ add timerovider polyfill for netstandard2
aicia-bot Aug 5, 2026
27e2f1e
🎨 modernize type inference in condition validator
aicia-bot Aug 5, 2026
0947b23
♻️ refactor maximum attempts to simplified non-nullable design
aicia-bot Aug 5, 2026
36f59d2
♻️ remove timeprovider from async run options
aicia-bot Aug 5, 2026
8601a68
⚡️ optimize Awaiter timeout handling with benchmark results
aicia-bot Aug 5, 2026
83fd43b
🐛 fix fractional-millisecond delay rounding in retry logic
aicia-bot Aug 5, 2026
b458d0d
✅ refactor file provider change notification assertions
aicia-bot Aug 5, 2026
f3620d3
✨ add fileProviders.physical benchmarks
aicia-bot Aug 5, 2026
7554051
🐛 fix filwatcher initialization and modified detection
aicia-bot Aug 5, 2026
7fb0867
🐛 fix awaiter timeout handling when delay exceeds window
aicia-bot Aug 5, 2026
7a8393e
♻️ convert primary constructor to traditional constructor
aicia-bot Aug 5, 2026
cf0e663
📝 add portablePhysicalFileProvider benchmark report
aicia-bot Aug 5, 2026
54a52d5
✨ add PortablePhysicalFileProvider with caching
aicia-bot Aug 6, 2026
d1462b4
✅ add PortablePhysicalFileProvider tests
aicia-bot Aug 6, 2026
f02e75f
✅ add PortablePhysicalFileProvider benchmarks
aicia-bot Aug 6, 2026
6660b4b
📝 update api documentation for file providers
aicia-bot Aug 6, 2026
00e474f
📦 update package metadata for 10.6.0 release
aicia-bot Aug 6, 2026
64062e6
💬 release version 10.6.0
aicia-bot Aug 6, 2026
c4ab99e
✅ refactor FileDependencyTest for improved async handling
aicia-bot Aug 6, 2026
20f4f96
✅ update AwaiterTest threading tests
aicia-bot Aug 6, 2026
fa05ad8
⚡️ optimize PortablePhysicalFileProviderBenchmark setup
aicia-bot Aug 6, 2026
bf1ea4a
📦 update PortablePhysicalFileProvider benchmark reports
aicia-bot Aug 6, 2026
f83b37c
🚨 remove outdated and false-positive analyzer suppressions
aicia-bot Aug 6, 2026
0a12afc
🎨 modernize null-check pattern to null-coalescing
aicia-bot Aug 6, 2026
7497d57
🚨 add namespace mismatch suppressions
gimlichael Aug 6, 2026
6cc9c44
♻️ use file-scoped namespaces throughout codebase
aicia-bot Aug 6, 2026
2677d16
📝 update 10.6.0 changelog entries
gimlichael Aug 6, 2026
2a29bf1
📝 update 10.6.0 release notes
gimlichael Aug 7, 2026
d09a69c
📝 refine 10.6.0 package release notes
gimlichael Aug 7, 2026
e528b37
🐛 improve async operation resilience with cancellation tokens and str…
aicia-bot Aug 7, 2026
9ef2bbc
🐛 skip framework moniker test when run in incompatible environment
aicia-bot Aug 7, 2026
dec48ef
✅ add DTD rejection test for XML encoding detection
aicia-bot Aug 7, 2026
fe933c9
📦 add bug fix entries to 10.6.0 package release notes
aicia-bot Aug 7, 2026
99b13c2
💬 document async resilience improvements and DTD rejection
aicia-bot Aug 7, 2026
29c192f
✅ capture domain snapshot after resolving assemblies
gimlichael Aug 7, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
9 changes: 9 additions & 0 deletions .docfx/api/namespaces/Cuemon.Extensions.FileProviders.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
uid: Cuemon.Extensions.FileProviders
summary: *content
---
Resolve physical files and directories through the familiar `IFileProvider` abstraction while treating path segments case-insensitively across operating systems. Use this namespace when callers may supply different casing for the same content path and ambiguous case-only matches must be reported as not found instead of selecting an arbitrary entry. Start with `PortablePhysicalFileProvider` to inspect files, enumerate directories, or watch literal paths while retaining the underlying `PhysicalFileProvider` behavior for filters and polling. Successful paths are cached for the provider lifetime, while misses and collisions are intentionally re-evaluated on every call.

[!INCLUDE [availability-default](../../includes/availability-default.md)]

Complements: [Microsoft.Extensions.FileProviders.Physical namespace](https://learn.microsoft.com/en-us/dotnet/api/microsoft.extensions.fileproviders.physical) 🔗
2 changes: 1 addition & 1 deletion .docfx/api/namespaces/Cuemon.Reflection.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
uid: Cuemon.Reflection
summary: *content
---
Retrieve assembly metadata, inspect members and parameters, and resolve versioning schemes (traditional and semantic) without verbose reflection boilerplate. The `Cuemon.Reflection` namespace extends `Assembly`, `MemberInfo`, and `MethodInfo` through `IDecorator<T>` extension methods for attribute inspection, type discovery, and version resolution. Use these extensions when you need to check assembly build type, detect custom attributes, or inspect member metadata. Start with `HasAttribute<T>` on `IDecorator<MemberInfo>` for attribute detection, or `GetTypes` on `IDecorator<Assembly>` for type discovery.
Retrieve assembly metadata, inspect members and parameters, resolve versioning schemes (traditional and semantic), and map assemblies to target framework monikers without verbose reflection boilerplate. The `Cuemon.Reflection` namespace extends `Assembly`, `MemberInfo`, and `MethodInfo` through `IDecorator<T>` extension methods for attribute inspection, type discovery, and version resolution, and it includes `TargetFrameworkMoniker` for resolving short TFMs such as `net10.0` or `netstandard2.0`. Use these APIs when you need to check assembly build type, detect custom attributes, inspect member metadata, or determine which target framework an assembly was built for. Start with `HasAttribute<T>` on `IDecorator<MemberInfo>` for attribute detection, `GetTypes` on `IDecorator<Assembly>` for type discovery, or `TargetFrameworkMoniker.ResolveCurrent` for current-process TFM resolution.

[!INCLUDE [availability-default](../../includes/availability-default.md)]

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ example:
- *content
---

The following example demonstrates how to register `BasicAuthenticationHandler` with ASP.NET Core authentication services. It sets up a `ServiceCollection`, registers the handler with a custom authenticator callback that validates credentials against hardcoded values, and builds the service provider. The handler is then resolved from DI and its type name is written to the console, confirming the authentication pipeline wires up correctly.
The following example demonstrates how to register `BasicAuthenticationHandler` with ASP.NET Core authentication services. It sets up a `ServiceCollection`, registers the handler with a custom authenticator callback that validates credentials against hardcoded values, and builds the service provider. The handler is then resolved from DI and its configured realm is written to the console, confirming the authentication pipeline wires up correctly.

```csharp
using System;
Expand Down Expand Up @@ -41,7 +41,7 @@ public static class BasicAuthenticationHandlerExample
using var provider = services.BuildServiceProvider();
var handler = provider.GetRequiredService<BasicAuthenticationHandler>();

Console.WriteLine(handler.GetType().Name);
Console.WriteLine($"Authentication realm: {handler.Options.Realm}");
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ example:
- *content
---

The following example demonstrates how to register `DigestAuthenticationHandler` with ASP.NET Core authentication services. It configures DI with `INonceTracker`, registers a digest authentication scheme with a username/password lookup callback, and builds the service provider. The handler is resolved from DI and its type name is written to the console, verifying that digest authentication wiring is operational.
The following example demonstrates how to register `DigestAuthenticationHandler` with ASP.NET Core authentication services. It configures DI with `INonceTracker`, registers a digest authentication scheme with a username/password lookup callback, and builds the service provider. The handler is then resolved from DI and its configured realm is written to the console, verifying that digest authentication wiring is operational.

```csharp
using System;
Expand Down Expand Up @@ -41,7 +41,7 @@ public static class DigestAuthenticationHandlerExample
using var provider = services.BuildServiceProvider();
var handler = provider.GetRequiredService<DigestAuthenticationHandler>();

Console.WriteLine(handler.GetType().Name);
Console.WriteLine($"Authentication realm: {handler.Options.Realm}");
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ example:
- *content
---

The following example demonstrates how to register `HmacAuthenticationHandler` with ASP.NET Core authentication services. It creates a `ServiceCollection`, registers the handler under a custom HMAC scheme with a client ID/secret authenticator callback, and builds the service provider. The handler is resolved from DI and its type name is written to the console, confirming that HMAC authentication configuration works end-to-end.
The following example demonstrates how to register `HmacAuthenticationHandler` with ASP.NET Core authentication services. It creates a `ServiceCollection`, registers the handler under a custom HMAC scheme with a client ID/secret authenticator callback, and builds the service provider. The handler is resolved from DI and its configured scheme is written to the console, confirming that HMAC authentication configuration works end-to-end.

```csharp
using System;
Expand Down Expand Up @@ -40,7 +40,7 @@ public static class HmacAuthenticationHandlerExample
using var provider = services.BuildServiceProvider();
var handler = provider.GetRequiredService<HmacAuthenticationHandler>();

Console.WriteLine(handler.GetType().Name);
Console.WriteLine($"Authentication scheme: {handler.Options.AuthenticationScheme}");
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,14 @@ public static class BadRequestExceptionExample
{
public static void Demonstrate()
{
var missingFields = new[] { "email", "displayName" };
var exception = new BadRequestException(
"The JSON payload is missing the required 'email' field.",
$"The JSON payload is missing required fields: {string.Join(", ", missingFields)}.",
new FormatException("Unexpected end of JSON input."));

Console.WriteLine(exception.StatusCode);
Console.WriteLine(exception.InnerException?.GetType().Name);
Console.WriteLine(exception.Message);
Console.WriteLine(exception.InnerException?.Message);
}
}
```
10 changes: 6 additions & 4 deletions .docfx/api/types/Cuemon.AspNetCore.Http.ConflictException.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ example:
- *content
---

The following example demonstrates how to use <xref cref="Cuemon.AspNetCore.Http.ConflictException"/> to signal HTTP 409 Conflict responses.
The following example demonstrates how to use <xref cref="Cuemon.AspNetCore.Http.ConflictException"/> to signal HTTP 409 Conflict responses. It compares the default, custom-message, inner-exception, and status-code parsing paths before applying a timestamp check that represents optimistic concurrency in an application service. The console output exposes the status code, reason phrase, and caller-facing message that an API exception handler can return to a client.

```csharp
using System;
Expand All @@ -29,13 +29,14 @@ public class ConflictExceptionExample
// Create with inner exception
var inner = new InvalidOperationException("Duplicate key violation.");
var withInner = new ConflictException("Resource update conflict.", inner);
Console.WriteLine(withInner.InnerException?.GetType().Name); // InvalidOperationException
Console.WriteLine(withInner.InnerException?.Message); // Duplicate key violation.

// Use TryParse from the base class to resolve by status code
if (HttpStatusCodeException.TryParse(409, out var parsed))
{
Console.WriteLine(parsed.GetType().Name); // ConflictException
Console.WriteLine(parsed.Message); // The request could not be completed due to a conflict.
Console.WriteLine(parsed.StatusCode); // 409
}

// Simulate a conflict check without throwing
var dbTimestamp = DateTime.UtcNow;
Expand All @@ -46,7 +47,8 @@ public class ConflictExceptionExample
"The resource was modified by another user. Please refresh and retry.");
Console.WriteLine(conflict.Message); // The resource was modified by another user...

}}}
}
}
}

```
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,14 @@ public class PayloadTooLargeExceptionExample
// Create with inner exception
var inner = new InvalidOperationException("Stream exceeded configured limit.");
var withInner = new PayloadTooLargeException("Request entity too large.", inner);
Console.WriteLine(withInner.InnerException?.GetType().Name); // InvalidOperationException
Console.WriteLine(withInner.InnerException?.Message); // Stream exceeded configured limit.

// Use TryParse from the base class to resolve by status code
if (HttpStatusCodeException.TryParse(413, "File exceeds 10 MB limit.", out var parsed))
{
Console.WriteLine(parsed.GetType().Name); // PayloadTooLargeException
Console.WriteLine(parsed.StatusCode); // 413
Console.WriteLine(parsed.Message); // File exceeds 10 MB limit.
Console.WriteLine(parsed.StatusCode); // 413
}

// Simulate a payload size check
long uploadSize = 15 * 1024 * 1024; // 15 MB
Expand All @@ -47,7 +47,8 @@ public class PayloadTooLargeExceptionExample
$"Upload of {uploadSize / 1024 / 1024} MB exceeds the {maxSize / 1024 / 1024} MB limit.");
Console.WriteLine(rejected.Message);

}}}
}
}
}

```
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,18 @@ public static class PreconditionFailedExceptionExample
{
public static void Demonstrate()
{
var exception = new PreconditionFailedException(
"The supplied If-Match value does not match the current ETag.",
new InvalidOperationException("ETag mismatch."));
const string currentEtag = "\"v2\"";
const string suppliedEtag = "\"v1\"";
if (!string.Equals(suppliedEtag, currentEtag, StringComparison.Ordinal))
{
var exception = new PreconditionFailedException(
$"The supplied If-Match value {suppliedEtag} does not match the current ETag {currentEtag}.",
new InvalidOperationException("The resource changed after the client read it."));

Console.WriteLine(exception.StatusCode);
Console.WriteLine(exception.InnerException?.Message);
Console.WriteLine(exception.StatusCode);
Console.WriteLine(exception.Message);
Console.WriteLine(exception.InnerException?.Message);
}
}
}
```
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,14 @@ public class TooManyRequestsExceptionExample
// Create with inner exception
var inner = new InvalidOperationException("Request quota exceeded.");
var withInner = new TooManyRequestsException("API rate limit reached.", inner);
Console.WriteLine(withInner.InnerException?.GetType().Name); // InvalidOperationException
Console.WriteLine(withInner.InnerException?.Message); // Request quota exceeded.

// Use TryParse from the base class to resolve by status code
if (HttpStatusCodeException.TryParse(429, "Slow down!", out var parsed))
{
Console.WriteLine(parsed.GetType().Name); // TooManyRequestsException
Console.WriteLine(parsed.StatusCode); // 429
Console.WriteLine(parsed.Message); // Slow down!
Console.WriteLine(parsed.StatusCode); // 429
}

// Simulate a rate-limit check using the RetryAfter header
var requestCount = 101;
Expand All @@ -49,7 +49,8 @@ public class TooManyRequestsExceptionExample
Console.WriteLine(rateLimited.Message); // Request #101 exceeds the limit...
Console.WriteLine(rateLimited.Headers["Retry-After"]); // 60

}}}
}
}
}

```
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,14 @@ public static class UnauthorizedExceptionExample
{
public static void Demonstrate()
{
const string authenticationScheme = "Bearer";
var exception = new UnauthorizedException(
"The request is missing a valid bearer token.",
$"The request is missing a valid {authenticationScheme} token.",
new InvalidOperationException("Token validation failed."));

Console.WriteLine(exception.StatusCode);
Console.WriteLine(exception.InnerException?.GetType().Name);
Console.WriteLine(exception.Message);
Console.WriteLine(exception.InnerException?.Message);
}
}
```
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public static class ServerTimingFilterExample
loggerFactory.CreateLogger<ServerTimingFilter>());

Console.WriteLine(filter.Options.UseTimeMeasureProfiler);
Console.WriteLine(filter.GetType().Name);
Console.WriteLine(filter.Options.SuppressHeaderPredicate is not null);
}

private sealed class SampleHostEnvironment : IHostEnvironment
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,13 @@ public static class AppImageTagHelperExample
{
var options = Options.Create(CreateOptions());

var tagHelper = new AppImageTagHelper(options);
var tagHelper = new AppImageTagHelper(options)
{
Src = "images/logo.svg",
Alt = "Codebelt logo"
};

Console.WriteLine(FormatAssetUrl(options.Value, "images/logo.svg"));
Console.WriteLine(tagHelper.GetType().Name);
Console.WriteLine(FormatAssetUrl(tagHelper.Options, tagHelper.Src));
}

private static AppTagHelperOptions CreateOptions() => new()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,13 @@ public static class AppLinkTagHelperExample
};

var version = new StylesheetVersion();
var tagHelper = new AppLinkTagHelper(Options.Create(options), version);
var stylesheetHref = $"{options.GetFormattedBaseUrl()}css/site.css?v={version.Version}";
var tagHelper = new AppLinkTagHelper(Options.Create(options), version)
{
Href = "css/site.css"
};
var stylesheetHref = $"{tagHelper.Options.GetFormattedBaseUrl()}{tagHelper.Href}?v={version.Version}";

Console.WriteLine(stylesheetHref);
Console.WriteLine(tagHelper.GetType().Name);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ The following example demonstrates how to create <xref cref="Cuemon.AspNetCore.R

```csharp
using System;
using System.Collections.Generic;
using Cuemon.AspNetCore.Razor.TagHelpers;
using Microsoft.Extensions.Options;

Expand All @@ -24,15 +23,13 @@ public static class AppScriptTagHelperExample
BaseUrl = "static.cuemon.net"
});

var tagHelper = new AppScriptTagHelper(options);
var segments = new List<string>
var tagHelper = new AppScriptTagHelper(options)
{
options.Value.GetFormattedBaseUrl(),
"js/app.js"
Src = "js/app.js",
Defer = true
};

Console.WriteLine(string.Concat(segments));
Console.WriteLine(tagHelper.GetType().Name);
Console.WriteLine(string.Concat(tagHelper.Options.GetFormattedBaseUrl(), tagHelper.Src));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,14 @@ public static class CdnImageTagHelperExample
};

var version = new AssetVersion();
var tagHelper = new CdnImageTagHelper(Options.Create(settings), version);
var imageUrl = settings.GetFormattedBaseUrl() + "images/logo.svg?v=" + version.Version;
var tagHelper = new CdnImageTagHelper(Options.Create(settings), version)
{
Src = "images/logo.svg",
Alt = "Codebelt logo"
};
var imageUrl = tagHelper.Options.GetFormattedBaseUrl() + tagHelper.Src + "?v=" + version.Version;

Console.WriteLine(imageUrl);
Console.WriteLine(tagHelper.GetType().Name);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,13 @@ public static class CdnLinkTagHelperExample
{
var options = Options.Create(CreateStylesheetOptions("nblcdn.net"));

var tagHelper = new CdnLinkTagHelper(options);
var stylesheetHref = options.Value.GetFormattedBaseUrl() + "packages/fontawesome/5.15.3/css/all.css";
var tagHelper = new CdnLinkTagHelper(options)
{
Href = "packages/fontawesome/5.15.3/css/all.css"
};
var stylesheetHref = tagHelper.Options.GetFormattedBaseUrl() + tagHelper.Href;

Console.WriteLine(stylesheetHref);
Console.WriteLine(tagHelper.GetType().Name);
}

private static CdnTagHelperOptions CreateStylesheetOptions(string baseUrl)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,14 @@ public static class CdnScriptTagHelperExample
});

var cacheBusting = new ScriptVersion();
var tagHelper = new CdnScriptTagHelper(options, cacheBusting);
var scriptPath = string.Concat(options.Value.GetFormattedBaseUrl(), "packages/fontawesome/5.15.3/js/all.js?v=", cacheBusting.Version);
var tagHelper = new CdnScriptTagHelper(options, cacheBusting)
{
Src = "packages/fontawesome/5.15.3/js/all.js",
Defer = true
};
var scriptPath = string.Concat(tagHelper.Options.GetFormattedBaseUrl(), tagHelper.Src, "?v=", cacheBusting.Version);

Console.WriteLine(scriptPath);
Console.WriteLine(tagHelper.GetType().Name);
}
}

Expand Down
Loading
Loading