Overview
Cuemon.AspNetCore.App is a metadata-only convenience package that brings the ASP.NET Core-focused parts of Cuemon under one install. It is aimed at applications that want authentication helpers, cache-busting support, cacheable MVC results, Razor TagHelpers, Razor Pages helpers, and JSON or XML formatter integrations available immediately.
The package does not declare its own public types in source evidence. The value is the bundled surface area from the referenced packages, so consumers install one package and then work directly with the APIs owned by those referenced libraries.
Key APIs
Cuemon.AspNetCore.App does not add public or protected APIs of its own, so the usable entry points come from the packages it aggregates, including DynamicCacheBusting, BasicAuthorizationHeaderBuilder, WithLastModifiedHeader, AddBasic, GetAppUrl, and the JSON or XML formatter and converter types exposed by the referenced ASP.NET Core packages.
Basic usage
These examples show the package areas that become available when you install Cuemon.AspNetCore.App.
Cuemon.AspNetCore
using System;
using Codebelt.Extensions.Xunit;
using Cuemon.AspNetCore.Configuration;
using Microsoft.Extensions.Options;
using Xunit;
namespace MyProject.Tests;
public class DynamicCacheBustingTest : Test
{
public DynamicCacheBustingTest(ITestOutputHelper output) : base(output)
{
}
[Fact]
public void ShouldReuseVersionWithinConfiguredTtl()
{
var sut = new DynamicCacheBusting(Options.Create(new DynamicCacheBustingOptions
{
PreferredLength = 10,
TimeToLive = TimeSpan.FromMinutes(5)
}));
var first = sut.Version;
var second = sut.Version;
TestOutput.WriteLine($"Cache-busting token: {first}");
Assert.Equal(first, second);
Assert.Equal(10, first.Length);
}
}
Cuemon.AspNetCore.Authentication
using Codebelt.Extensions.Xunit;
using Cuemon.AspNetCore.Authentication.Basic;
using Xunit;
namespace MyProject.Tests;
public class BasicAuthorizationHeaderBuilderTest : Test
{
public BasicAuthorizationHeaderBuilderTest(ITestOutputHelper output) : base(output)
{
}
[Fact]
public void ShouldBuildBasicAuthorizationHeader()
{
var sut = new BasicAuthorizationHeaderBuilder();
BasicAuthorizationHeader header = sut
.AddUserName("agent")
.AddPassword("secret123")
.Build();
TestOutput.WriteLine(header.ToString());
Assert.Equal("agent", header.UserName);
Assert.Equal("secret123", header.Password);
Assert.StartsWith("Basic ", header.ToString());
}
}
Cuemon.AspNetCore.Mvc
using System;
using Codebelt.Extensions.Xunit;
using Cuemon.AspNetCore.Mvc;
using Cuemon.Data.Integrity;
using Cuemon.Extensions.AspNetCore.Mvc;
using Xunit;
namespace MyProject.Tests;
public class CacheableMvcResultTest : Test
{
public CacheableMvcResultTest(ITestOutputHelper output) : base(output)
{
}
[Fact]
public void ShouldWrapValueWithLastModifiedMetadata()
{
var payload = "asset-manifest";
var cacheable = payload.WithLastModifiedHeader(o =>
{
o.TimestampProvider = _ => DateTime.MinValue;
o.ChangedTimestampProvider = _ => DateTime.MaxValue;
});
var timestamps = Assert.IsAssignableFrom<IEntityDataTimestamp>(cacheable);
TestOutput.WriteLine($"Created: {timestamps.Created:o}, Modified: {timestamps.Modified:o}");
Assert.Equal(payload, cacheable.Value);
Assert.Equal(DateTime.MinValue, timestamps.Created);
Assert.Equal(DateTime.MaxValue, timestamps.Modified);
}
}
Cuemon.AspNetCore.Razor.TagHelpers
using System.Threading.Tasks;
using Codebelt.Extensions.Xunit;
using Cuemon.AspNetCore.Configuration;
using Cuemon.AspNetCore.Razor.TagHelpers;
using Microsoft.Extensions.Options;
using Xunit;
namespace MyProject.Tests;
public class AppImageTagHelperTest : Test
{
public AppImageTagHelperTest(ITestOutputHelper output) : base(output)
{
}
[Fact]
public void ShouldUseConfiguredBaseUrlForApplicationAssets()
{
var sut = new AppImageTagHelper(Options.Create(new AppTagHelperOptions
{
BaseUrl = "static.example.com",
Scheme = ProtocolUriScheme.Relative
}), new FixedCacheBusting());
TestOutput.WriteLine(sut.Options.GetFormattedBaseUrl());
Assert.Equal("static.example.com", sut.Options.BaseUrl);
Assert.Equal("//static.example.com/", sut.Options.GetFormattedBaseUrl());
}
private sealed class FixedCacheBusting : ICacheBusting
{
public string Version => "00000000000000000000000000000000";
}
}
Cuemon.Extensions.AspNetCore
using Codebelt.Extensions.Xunit;
using Cuemon.Extensions.AspNetCore.Configuration;
using Microsoft.Extensions.Options;
using Xunit;
namespace MyProject.Tests;
public class AssemblyCacheBustingTest : Test
{
public AssemblyCacheBustingTest(ITestOutputHelper output) : base(output)
{
}
[Fact]
public void ShouldComputeVersionFromAssembly()
{
var sut = new AssemblyCacheBusting(Options.Create(new AssemblyCacheBustingOptions
{
Assembly = typeof(AssemblyCacheBustingTest).Assembly
}));
TestOutput.WriteLine(sut.Version);
Assert.NotNull(sut.Version);
Assert.NotEmpty(sut.Version);
}
}
Cuemon.Extensions.AspNetCore.Authentication
using System.Security.Claims;
using Codebelt.Extensions.Xunit;
using Cuemon.AspNetCore.Authentication.Basic;
using Cuemon.Extensions.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Xunit;
namespace MyProject.Tests;
public class AuthenticationBuilderExtensionsTest : Test
{
public AuthenticationBuilderExtensionsTest(ITestOutputHelper output) : base(output)
{
}
[Fact]
public void ShouldRegisterBasicAuthenticationScheme()
{
var services = new ServiceCollection();
services
.AddAuthentication(BasicAuthorizationHeader.Scheme)
.AddBasic(o => o.Authenticator = (username, password) =>
new ClaimsPrincipal(new ClaimsIdentity(new[]
{
new Claim(ClaimTypes.Name, username)
}, BasicAuthorizationHeader.Scheme)));
var provider = services.BuildServiceProvider();
var options = provider.GetRequiredService<IOptionsMonitor<BasicAuthenticationOptions>>()
.Get(BasicAuthorizationHeader.Scheme);
TestOutput.WriteLine($"Realm: {options.Realm}");
Assert.NotNull(options.Authenticator);
Assert.Equal("AuthenticationServer", options.Realm);
}
}
Cuemon.Extensions.AspNetCore.Mvc
using Codebelt.Extensions.Xunit;
using Cuemon.AspNetCore.Mvc;
using Cuemon.Data.Integrity;
using Cuemon.Extensions.AspNetCore.Mvc;
using Xunit;
namespace MyProject.Tests;
public class CacheableObjectResultExtensionsTest : Test
{
public CacheableObjectResultExtensionsTest(ITestOutputHelper output) : base(output)
{
}
[Fact]
public void ShouldWrapValueWithEntityTagMetadata()
{
var payload = "asset-manifest";
var checksum = new byte[] { 1, 2, 3, 4 };
var cacheable = payload.WithEntityTagHeader(o =>
{
o.ChecksumProvider = _ => checksum;
o.WeakChecksumProvider = _ => false;
});
var integrity = Assert.IsAssignableFrom<IEntityDataIntegrity>(cacheable);
TestOutput.WriteLine($"Validation: {integrity.Validation}");
Assert.Equal(payload, cacheable.Value);
Assert.Equal(EntityDataIntegrityValidation.Strong, integrity.Validation);
Assert.NotNull(integrity.Checksum);
}
}
Cuemon.Extensions.AspNetCore.Mvc.Formatters.Text.Json
using Codebelt.Extensions.Xunit;
using Cuemon.Extensions.AspNetCore.Mvc.Formatters.Text.Json;
using Cuemon.Extensions.Text.Json.Formatters;
using Xunit;
namespace MyProject.Tests;
public class JsonSerializationOutputFormatterTest : Test
{
public JsonSerializationOutputFormatterTest(ITestOutputHelper output) : base(output)
{
}
[Fact]
public void ShouldExposeConfiguredJsonMediaTypes()
{
var options = new JsonFormatterOptions();
var sut = new JsonSerializationOutputFormatter(options);
TestOutput.WriteLine($"JSON media types: {string.Join(", ", options.SupportedMediaTypes)}");
Assert.IsType<JsonSerializationOutputFormatter>(sut);
Assert.Contains(options.SupportedMediaTypes, mediaType => mediaType.ToString() == "application/json");
}
}
Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml
using Codebelt.Extensions.Xunit;
using Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml;
using Cuemon.Xml.Serialization.Formatters;
using Xunit;
namespace MyProject.Tests;
public class XmlSerializationOutputFormatterTest : Test
{
public XmlSerializationOutputFormatterTest(ITestOutputHelper output) : base(output)
{
}
[Fact]
public void ShouldExposeConfiguredXmlMediaTypes()
{
var options = new XmlFormatterOptions();
var sut = new XmlSerializationOutputFormatter(options);
TestOutput.WriteLine($"XML media types: {string.Join(", ", options.SupportedMediaTypes)}");
Assert.IsType<XmlSerializationOutputFormatter>(sut);
Assert.Contains(options.SupportedMediaTypes, mediaType => mediaType.ToString() == "application/xml");
}
}
Cuemon.Extensions.AspNetCore.Mvc.RazorPages
using Codebelt.Extensions.Xunit;
using Cuemon.AspNetCore.Configuration;
using Cuemon.AspNetCore.Razor.TagHelpers;
using Cuemon.Extensions.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.DependencyInjection;
using Xunit;
namespace MyProject.Tests;
public class PageBaseExtensionsTest : Test
{
public PageBaseExtensionsTest(ITestOutputHelper output) : base(output)
{
}
[Fact]
public void ShouldBuildApplicationAssetUrlFromPageModel()
{
var services = new ServiceCollection();
services.Configure<AppTagHelperOptions>(o =>
{
o.Scheme = ProtocolUriScheme.Relative;
o.BaseUrl = "static.example.com";
});
services.AddSingleton<ICacheBusting>(new FixedCacheBusting());
var page = new StubPage
{
PageContext = new PageContext
{
HttpContext = new DefaultHttpContext
{
RequestServices = services.BuildServiceProvider()
}
}
};
var url = page.GetAppUrl("css/site.css");
TestOutput.WriteLine(url);
Assert.Equal("//static.example.com/css/site.css?v=00000000000000000000000000000000", url);
}
private sealed class StubPage : PageBase
{
public override Task ExecuteAsync() => Task.CompletedTask;
}
private sealed class FixedCacheBusting : ICacheBusting
{
public string Version => "00000000000000000000000000000000";
}
}
Cuemon.Extensions.AspNetCore.Text.Json
using System.Collections.Generic;
using System.Text.Json.Serialization;
using Codebelt.Extensions.Xunit;
using Cuemon.Extensions.AspNetCore.Text.Json.Converters;
using Xunit;
namespace MyProject.Tests;
public class JsonConverterCollectionExtensionsTest : Test
{
public JsonConverterCollectionExtensionsTest(ITestOutputHelper output) : base(output)
{
}
[Fact]
public void ShouldRegisterStringValuesJsonConverter()
{
var converters = new List<JsonConverter>();
var returned = converters.AddStringValuesConverter();
TestOutput.WriteLine($"Registered converters: {converters.Count}");
Assert.Same(converters, returned);
Assert.Single(converters);
}
}
Cuemon.Extensions.AspNetCore.Xml
using System.Collections.Generic;
using Codebelt.Extensions.Xunit;
using Cuemon.Extensions.AspNetCore.Xml.Converters;
using Cuemon.Xml.Serialization.Converters;
using Xunit;
namespace MyProject.Tests;
public class XmlConverterExtensionsTest : Test
{
public XmlConverterExtensionsTest(ITestOutputHelper output) : base(output)
{
}
[Fact]
public void ShouldRegisterStringValuesXmlConverter()
{
var converters = new List<XmlConverter>();
var returned = converters.AddStringValuesConverter();
TestOutput.WriteLine($"Registered converters: {converters.Count}");
Assert.Same(converters, returned);
Assert.Single(converters);
}
}
Installing Cuemon.AspNetCore.App gives you one NuGet reference, but the APIs shown above are owned by the referenced packages rather than by the aggregate package itself. Use the aggregate package when you want this ASP.NET Core-focused surface together, and move to the smaller packages directly when you want tighter dependency selection.
Installation
dotnet add package Cuemon.AspNetCore.App
Usage guidance
Choose Cuemon.AspNetCore.App when an application wants the broader Cuemon ASP.NET Core stack available through one package reference, especially when authentication helpers, MVC caching primitives, Razor asset helpers, and JSON or XML formatter integrations all belong in the same solution. If you only need one of those areas, reference the smaller package directly so your project only carries the APIs and dependencies it actually uses.
Family packages
- 🌐Cuemon.AspNetCore
- 🌐Cuemon.AspNetCore.Authentication
- 🌐Cuemon.AspNetCore.Mvc
- 🌐Cuemon.AspNetCore.Razor.TagHelpers
- 📦Cuemon.Core
- 🏭Cuemon.Core.App
- 🗄️Cuemon.Data
- 🗄️Cuemon.Data.Integrity
- 🗄️Cuemon.Data.SqlClient
- 🩺Cuemon.Diagnostics
- 🌐Cuemon.Extensions.AspNetCore
- 🌐Cuemon.Extensions.AspNetCore.Authentication
- 🌐Cuemon.Extensions.AspNetCore.Mvc
- 🌐Cuemon.Extensions.AspNetCore.Mvc.Formatters.Text.Json
- 🌐Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml
- 🌐Cuemon.Extensions.AspNetCore.Mvc.RazorPages
- 🌐Cuemon.Extensions.AspNetCore.Text.Json
- 🌐Cuemon.Extensions.AspNetCore.Xml
- 📦Cuemon.Extensions.Collections.Generic
- 📦Cuemon.Extensions.Collections.Specialized
- 📦Cuemon.Extensions.Core
- 🗄️Cuemon.Extensions.Data
- 🗄️Cuemon.Extensions.Data.Integrity
- 📦Cuemon.Extensions.DependencyInjection
- 🩺Cuemon.Extensions.Diagnostics
- 🏗️Cuemon.Extensions.Hosting
- 📦Cuemon.Extensions.IO
- 📦Cuemon.Extensions.Net
- 📦Cuemon.Extensions.Reflection
- 📦Cuemon.Extensions.Runtime.Caching
- 📝Cuemon.Extensions.Text
- 📝Cuemon.Extensions.Text.Json
- 📦Cuemon.Extensions.Threading
- 📦Cuemon.Extensions.Xml
- 📦Cuemon.IO
- ⚙️Cuemon.Kernel
- 📦Cuemon.Net
- 📦Cuemon.Resilience
- 📦Cuemon.Runtime.Caching
- 🔐Cuemon.Security.Cryptography
- 📦Cuemon.Threading
- 📦Cuemon.Xml