惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

L
LangChain Blog
阮一峰的网络日志
阮一峰的网络日志
WordPress大学
WordPress大学
博客园 - 司徒正美
罗磊的独立博客
D
Docker
Last Week in AI
Last Week in AI
爱范儿
爱范儿
M
MIT News - Artificial intelligence
V
V2EX
Google DeepMind News
Google DeepMind News
小众软件
小众软件
Apple Machine Learning Research
Apple Machine Learning Research
Microsoft Security Blog
Microsoft Security Blog
T
Tailwind CSS Blog
MyScale Blog
MyScale Blog
V
Visual Studio Blog
博客园 - 叶小钗
B
Blog RSS Feed
A
About on SuperTechFans
F
Fortinet All Blogs
T
The Blog of Author Tim Ferriss
Martin Fowler
Martin Fowler
P
Proofpoint News Feed

博客园 - dudu

test .NET CQRS 的实现中引入 ReadOnlyRepository 初试 .NET CQRS 开源库 LiteBus 什么是 Agentic ? 初试 Microsoft Agent Framework 初识 Microsoft Agent Framework:一句话介绍 ASP.NET Core 中读取 UserAgent 的正确姿势 C# 实现通用的 IdEqualityComparer 用 Angular Signal Inputs 完成一个组件的重构 量子网络操作系统 QNodeOS 资料收集 Kubernetes 集群上部署 Open WebUI 在 Kubernetes 集群的 GPU 节点上部署 Ollama 尝试在 Kubernetes 集群上用阿里云 GPU 实例部署 Ollama + DeekSeek-R1 阿里云 GPU 实例云服务器本地部署 DeepSeek R1 尝试使用阿里云计算巢部署 DeepSeek-R1 Angular 中依赖注入问题造成 Observable 订阅不更新 园子博客后台 Angular 升级:手工迁移至 Standalone Component Angular 中使用 ChildContent 记录 园子博客后台升级至 angular 19 后 eslint 9 迁移记录 学习大模型(LLM)的英文好文收集
记录一下对 ASP.NET Core Middleware 进行单元测试的代码
dudu · 2025-07-30 · via 博客园 - dudu

Middleware 实现的功能是从请求的 hostname 中读取 subdomain,然后根据 blog 的配置,进行 url 重写或者重定向,实现代码如下

public class SubdomainMiddleware(
    RequestDelegate next,
    IBlogQueryService blogQuery,
    IOptions<SiteOptions> siteOptions)
{
    public async Task InvokeAsync(HttpContext context)
    {
        var request = context.Request;
        var currentHost = request.Host.Host.AsSpan();
        var defaultHost = new HostString(siteOptions.Value.Host);

        if (CommonUrlHelper.TryParseBlogAppFromHostname(currentHost, out var blogApp))
        {
            var path = request.Path.Value;

            if (await blogQuery.IsSubdomainBlog(blogApp))
            {
                request.Host = defaultHost;
                path = path == "/" ? string.Empty : request.Path;
                request.Path = $"/{blogApp}{path}";
            }
            else
            {
                var newUrl = UriHelper.BuildAbsolute("https", defaultHost, request.PathBase, $"/{blogApp}{request.Path}", request.QueryString);
                context.Response.Redirect(newUrl, false);
                return;
            }
        }

        await next(context);
    }
}

基于 TestServer 构建 middlewrite pipeline 的代码

private static async Task<WebApplication> BuildApp()
{
    var builder = WebApplication.CreateBuilder();
    MockBlogQueryService(builder.Services);
    MockSiteOptions(builder.Services);
    builder.WebHost.UseTestServer();
    var app = builder.Build();
    app.UseMiddleware<SubdomainMiddleware>();
    app.Run(async context => await context.Response.WriteAsync(context.Request.GetDisplayUrl()));
    await app.StartAsync();
    return app;
}

Mock 中间件所用到的接口

private static void MockBlogQueryService(IServiceCollection services)
{
    services.Mock<IBlogQueryService>(
        mock => mock.Setup(x => x.IsSubdomainBlog("dudu")).ReturnsAsync(true),
        ServiceLifetime.Scoped);
}

private static void MockSiteOptions(IServiceCollection services)
{
    services.Mock<IOptions<SiteOptions>>(
        mock => mock.Setup(x => x.Value).Returns(new SiteOptions()),
        ServiceLifetime.Scoped);
}

Url 重写的测试用例

[Fact]
public async Task Rewrite_subdomain_blog_url()
{
    // Arrange
    await using var app = await BuildApp();

    // Act
    var client = app.GetTestClient();
    var response = await client.GetAsync("https://dudu.cnblogs.com/p/18637966");

    // Assert
    Assert.Equal(HttpStatusCode.OK, response.StatusCode);
    Assert.Equal("https://www.cnblogs.com/dudu/p/18637966", await response.Content.ReadAsStringAsync());
}

Url 重定向的测试用例

[Fact]
public async Task Redirect_non_subdomain_blog()
{
    // Arrange
    await using var app = await BuildApp();

    // Act
    var client = app.GetTestClient();
    var response = await client.GetAsync("https://cmt.cnblogs.com/p/11391410.html");

    // Assert
    Assert.Equal(HttpStatusCode.Redirect, response.StatusCode);
    Assert.Equal("https://www.cnblogs.com/cmt/p/11391410.html", response.Headers.Location.ToString());
}