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

.NET 6控制台应用中Kestrel调用WriteAsync触发NullReferenceException

问题:调用HttpContext.Response.WriteAsync()触发NullReferenceException

我正在使用.NET 6开发Windows服务器,需要监听内网HTTP请求,因此选择了Kestrel。发送HTTP请求时,Kestrel能正常接收并让我在代码中处理请求,但调用HttpContext.Response.WriteAsync()发送响应时,会触发NullReferenceException。

堆栈跟踪如下:

at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.CreateResponseHeader(Boolean appCompleted)
at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.InitializeResponseAsync(Int32 firstWriteByteCount)
at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.WriteAsync(ReadOnlyMemory`1 data, CancellationToken cancellationToken)
at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpResponseStream.WriteAsync(Byte[] buffer, Int32 offset, Int32 count, CancellationToken cancellationToken)
at Microsoft.AspNetCore.Http.HttpResponseWritingExtensions.WriteAsync(HttpResponse response, String text, Encoding encoding, CancellationToken cancellationToken)
at Microsoft.AspNetCore.Http.HttpResponseWritingExtensions.WriteAsync(HttpResponse response, String text, CancellationToken cancellationToken)

我的服务注册代码:

IPAddress address = settings.BindAddress == null ? IPAddress.Any : IPAddress.Parse(settings.BindAddress);

services.Configure<KestrelServerOptions>(options =>
{
    options.Listen(address, settings.ListeningPort);
});

services.AddSingleton<IServer, KestrelServer>();
services.AddSingleton<ITransportFactory, SocketTransportFactory>();
services.AddSingleton<IApplicationLifetime, ApplicationLifetime>();
services.AddTransient<IHttpContextFactory, HttpContextFactory>();

实现IHttpApplication的处理类:

public class HttpController : IHttpApplication<HttpContext>
{
    private readonly IServer _server;
    private readonly ILogger<HttpController> _logger;
    private readonly IHttpContextFactory _httpContextFactory;
    
    public HttpController(IServer server, IHttpContextFactory httpContextFactory, ILogger<HttpController> logger)
    {
        _server = server;
        _httpContextFactory = httpContextFactory;
        _logger = logger;            
    }

    public async Task StartAsync(CancellationToken cancellationToken)
    {
        await Task.Yield();
        _server.StartAsync(this, cancellationToken);
    }

    public HttpContext CreateContext(IFeatureCollection contextFeatures)
    {
        return _httpContextFactory.Create(contextFeatures);
    }

    public void DisposeContext(HttpContext context, Exception exception)
    {
        _httpContextFactory.Dispose(context);
    }

    public async Task ProcessRequestAsync(HttpContext context)
    {
        _logger.LogInformation("{Method} Http request received: {Path}", context.Request.Method, context.Request.Path);
        
        try
        {
            if (context.Request.Path.StartsWithSegments("/hello"))
            {
                var resp = "Hello World!";
                await context.Response.WriteAsync(resp);                    
            }
        }
        catch(Exception ex)
        {
            _logger.LogError("Error while managing HTTP {Method} request to {Path} : {message}", context.Request.Method, context.Request.Path, ex.Message);
        }
    }
}

请问为何调用context.Response.WriteAsync()会触发这个NullReferenceException?


解决方案

问题原因

你手动注册IServer、ITransportFactory等核心服务的方式跳过了ASP.NET Core的标准初始化流程,导致HttpContext.Response的底层依赖(比如HttpProtocol内部的响应头相关对象)未被正确实例化。Kestrel需要一系列内部服务和特性支持才能完成响应的构建与发送,手动注册单个服务无法满足这些依赖要求,最终调用WriteAsync时触发空引用异常。

修复步骤

不要手动注册Kestrel相关的核心服务,改用ASP.NET Core提供的标准主机配置方式,它会自动注入所有必要的依赖:

  1. 修改服务注册与启动逻辑,使用Host.CreateDefaultBuilder搭配ConfigureWebHostDefaults来配置Kestrel:
var host = Host.CreateDefaultBuilder(args)
    .ConfigureWebHostDefaults(webBuilder =>
    {
        webBuilder.ConfigureKestrel(options =>
        {
            IPAddress address = settings.BindAddress == null ? IPAddress.Any : IPAddress.Parse(settings.BindAddress);
            options.Listen(address, settings.ListeningPort);
        });
        webBuilder.UseStartup<Startup>();
    })
    .Build();

await host.RunAsync();
  1. 创建Startup类,配置请求处理管道:
public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        // 添加必要的ASP.NET Core基础服务
        services.AddHttpContextAccessor();
        services.AddRouting();
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        // 配置请求管道,添加端点路由
        app.UseRouting();

        app.UseEndpoints(endpoints =>
        {
            endpoints.Map("/hello", async context =>
            {
                await context.Response.WriteAsync("Hello World!");
            });
        });
    }
}
  1. 如果必须保留IHttpApplication的实现,确保通过标准主机来启动,而非手动调用_server.StartAsync:
// 在Startup的Configure中可以替换为自定义的IHttpApplication
app.UseHttpApplication(new HttpController(...));

关键说明

ASP.NET Core的主机系统会自动处理Kestrel的初始化、服务依赖注入、请求管道构建等流程,手动注册核心服务会破坏这种依赖链,导致底层对象未初始化。使用标准配置方式能确保HttpContext的请求和响应对象都拥有完整的依赖支持,避免空引用异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 08:03:32