You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用RunOaktonCommands结合WebApplicationFactory测试时触发ObjectDisposedException

ASP.NET 测试中 Oakton 导致的对象已释放异常问题

问题场景

ASP.NET应用程序入口代码:

public sealed class Program
{
    public static async Task Main(params string[] args)
    {
        try
        {
            var builder = WebApplication.CreateBuilder(args);

            await using var app = builder
                .Build();

            app.UseRequestLocalization(
                new RequestLocalizationOptions
                {
                    DefaultRequestCulture = new RequestCulture("nl-NL"),
                });

            await app.RunOaktonCommands(args);
        }
        catch (Exception e)
        {
            Console.WriteLine(e);
            throw;
        }

    }
}

对应的单元测试代码:

public class Tests : WebApplicationFactory<WebApplication1.Program>
{
    protected override void ConfigureWebHost(IWebHostBuilder builder)
    {
        builder.UseEnvironment("UnitTest");
        builder.ConfigureLogging(l => l.AddConsole());
    }

    [Test]
    public async Task Test1()
    {
        Server.PreserveExecutionContext = true;
        using var client = CreateClient();
        
        Assert.Pass();
    }
}

执行测试时抛出System.ObjectDisposedException: Cannot access a disposed object. Object name: 'IServiceProvider'异常,替换app.RunOaktonCommands(args)为app.RunAsync()后测试正常通过。

原因分析

Oakton的RunOaktonCommands方法是为命令行工具任务设计的,任务执行完成后会直接触发WebApplication实例的释放(代码中await using声明会自动管理实例生命周期)。而WebApplicationFactory在测试流程中需要保持应用服务提供者(IServiceProvider)等资源的存活状态,两者生命周期管理逻辑冲突,导致测试时访问已被释放的对象。

解决方法

方案一:根据环境分支处理入口逻辑

在Main方法中判断当前环境,测试环境下跳过Oakton命令执行,改用RunAsync维持应用生命周期:

public static async Task Main(params string[] args)
{
    try
    {
        var builder = WebApplication.CreateBuilder(args);
        await using var app = builder.Build();

        app.UseRequestLocalization(
            new RequestLocalizationOptions
            {
                DefaultRequestCulture = new RequestCulture("nl-NL"),
            });

        // 判断是否为测试环境
        if (builder.Environment.IsEnvironment("UnitTest"))
        {
            await app.RunAsync();
        }
        else
        {
            await app.RunOaktonCommands(args);
        }
    }
    catch (Exception e)
    {
        Console.WriteLine(e);
        throw;
    }
}

方案二:调整WebApplicationFactory的配置(不推荐)

如果必须保留Oakton调用,可尝试在测试中阻止资源提前释放,但这种方式会破坏Oakton的原有设计,容易引入其他问题,因此更推荐方案一。

内容的提问来源于stack exchange,提问作者Gemberkoekje

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 04:18:13