.Net 6 控制台应用中的 Kestrel - 调用 HttpContext.Response.WriteAsync() 时出现 NullReferenceException

Kestrel in .Net 6 console App - NullReferenceException when calling HttpContext.Response.WriteAsync()

提问人:vbond007 提问时间:8/28/2022 更新时间:8/29/2022 访问量:487

问:

我正在使用 .Net 6 编写 Windows 服务器,我需要侦听内部网络 http 请求。 我决定使用红隼。 当我发送 http 请求时,一切都很好,Kestrel 接受该请求,我可以用代码管理它。 但是当我想通过 发送答案时,会启动 NullReferenceException。 堆栈跟踪如下:HttpContext.Response.WriteAsync()

在 Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.CreateResponseHeader(Boolean appCompleted) 在 Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.InitializeResponseAsync(Int32 firstWriteByteCount) 在 Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.WriteAsync(ReadOnlyMemory'1 data, CancellationToken cancellationToken) 在 Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpResponseStream.WriteAsync(Byte[] 缓冲区、 Int32 偏移量、 Int32 计数、 CancellationToken cancellationToken) 在 Microsoft.AspNetCore.Http.HttpResponseWritingExtensions.WriteAsync(HttpResponse response、字符串文本、编码编码、CancellationToken cancellationToken) 在 Microsoft.AspNetCore.Http.HttpResponseWritingExtensions.WriteAsync(HttpResponse response, 字符串文本, 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;
    
    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);
        }
    }
}

知道为什么要启动这个 NullReferenceException 吗? 谢谢。context.Response.WriteAsync()

.NET 控制台 NullReferenceException Kestrel

评论


答:

0赞 vbond007 8/29/2022 #1

最后,经过 2 天的调查,我找到了解决方法。 我不得不使用包 Microsoft.AspNetCore.App。 然后我不得不添加这样的服务:

services.AddSingleton<IServer, KestrelServer>();
services.AddSingleton<IConnectionListenerFactory, SocketTransportFactory>();                        
services.AddTransient<IHttpContextFactory, DefaultHttpContextFactory>();

这意味着我必须删除该行。它由添加的包进行管理。 我不得不用 替换,我用 替换了......ApplicationLifeTimeITransportFactoryIConnectionListenerFactoryHttpContextFactoryDefaultHttpContextFactory

部分答案在这里找到: https://github.com/dotnet/aspnetcore/issues/28112