gpt4 book ai didi

c# - Web API 操作参数间歇性为空

转载 作者:行者123 更新时间:2023-11-30 12:29:35 25 4
gpt4 key购买 nike

相关问题:Web API ApiController PUT and POST methods receive null parameters intermittently

背景

在对现有 Web API 项目进行负载测试时,我注意到许多空引用异常是由于在发布到操作时参数为空而导致的。

原因似乎是在开发环境中运行时注册为记录请求的自定义消息处理程序。删除此处理程序可解决问题。

我知道在 Web API 中我只能读取一次请求正文并且读取它总是会导致我的参数为空,因为模型绑定(bind)将无法进行。出于这个原因,我使用 ReadAsStringAsync() 方法和 ContinueWith 来读取正文。看起来这在大约 0.2% 的请求中表现得很奇怪(在使用 Apache Bench 进行本地调试期间)。

代码

在最基本的层面上,我有以下几点:

模型

public class User
{
public string Name { get; set; }
}

API Controller

public class UsersController : ApiController
{
[HttpPost]
public void Foo(User user)
{
if (user == null)
{
throw new NullReferenceException();
}
}
}

消息处理程序

public class TestMessageHandler : DelegatingHandler
{
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
request.Content.ReadAsStringAsync().ContinueWith((task) =>
{
/* do stuff with task.Result */
});

return base.SendAsync(request, cancellationToken);
}
}

...在应用启动时注册

GlobalConfiguration.Configuration.MessageHandlers.Add(new TestMessageHandler());

我使用的是 WebAPI 4.0.30506.0,发布时的最新版本。该项目中的所有其他 MS 包也运行最新版本(下面链接的演示项目现已更新以反射(reflect)这一点)。

测试

初始测试是使用 Loadster 进行的在带有 .NET 4.0.30319 的 Server 2008 R2 上针对负载平衡的 IIS 7.5 设置运行。我正在使用 Apache Bench 在 Windows 7 上的 IIS 7.5 和 .NET 4.5.50709 上本地复制它。

ab -n 500 -c 25 -p testdata.post -T "application/json" http://localhost/ModelBindingFail/api/users/foo

testdata.post 包含

{ "Name":"James" }

通过此测试,我看到 500 个请求中大约有 1 个失败,所以约为 0.2%。

后续步骤...

我已将我的演示项目放在 GitHub 上如果您想自己尝试,尽管除了我上面发布的内容之外,它还是一个标准的空 Web API 项目。

也很乐意尝试任何建议或发布更多信息。谢谢!

最佳答案

我仍在调查这个问题的根本原因,但到目前为止,我的直觉是 ContinueWith() 正在不同的上下文中执行,或者在请求流已被处理的某个点或类似的地方(一次我确定我会更新这一段)。

就修复而言,我已经快速路测了三个可以无错误处理 500 个请求的方法。

最简单的是只使用 task.Result,但这确实有一些问题(它可以 apparently cause deadlocks ,尽管 YMMV)。

protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var result = request.Content.ReadAsStringAsync().Result;
return base.SendAsync(request, cancellationToken);
}

接下来,您可以确保您正确地链接了您的延续以避免任何关于上下文的歧义,但是它非常难看(而且我不能 100% 确定它是否没有副作用):

protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var result = request.Content.ReadAsStringAsync().ContinueWith(task =>
{
/* do stuff with task.Result */
});

return result.ContinueWith(t => base.SendAsync(request, cancellationToken)).Unwrap();
}

最后,最佳解决方案似乎是使用 async/await 到 sweep away any threading nasties ,显然,如果您卡在 .NET 4.0 上,这可能是个问题。

protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var content = await request.Content.ReadAsStringAsync();
Debug.WriteLine(content);
return await base.SendAsync(request, cancellationToken);
}

关于c# - Web API 操作参数间歇性为空,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18256817/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com