System.Web 从异步 ServiceStack 服务使用 GetAsync 调用 ServiceStack 服务时出现 NullReferenceException
NullReferenceException in System.Web calling ServiceStack service with GetAsync from async ServiceStack service
我有一个从上到下使用异步的 ServiceStack 服务。下面是一个简化的示例,所有层都折叠到服务定义。
public async Task<ReadItemResponse> Get(Dto.ReadItem request)
{
using (JsonServiceClient client = new JsonServiceClient("http://someserver/itemservice"))
{
ReadItemResponse response = await client.GetAsync(new ReadItem
{
ItemNumber = request.ItemNumber
});
return new Dto.ReadItemResponse
{
Item = new Dto.Item
{
ItemNumber = response.Item.ItemNumber,
ItemName = response.Item.ItemName
}
};
}
}
当我对服务进行大量并发调用时,上述代码会在 1 - 30 秒内在 System.Web 中引发 NullReferenceException。
System.Web.dll!System.Web.ThreadContext.AssociateWithCurrentThread(bool setImpersonationContext)
System.Web.dll!System.Web.HttpApplication.OnThreadEnterPrivate(bool setImpersonationContext)
System.Web.dll!System.Web.HttpApplication.System.Web.Util.ISyncContext.Enter()
System.Web.dll!System.Web.Util.SynchronizationHelper.SafeWrapCallback(System.Action action = {Method = {System.Reflection.RuntimeMethodInfo}})
System.Web.dll!System.Web.Util.SynchronizationHelper.QueueAsynchronous.AnonymousMethod__0(System.Threading.Tasks.Task _)
mscorlib.dll!System.Threading.Tasks.ContinuationTaskFromTask.InnerInvoke()
mscorlib.dll!System.Threading.Tasks.Task.Execute()
mscorlib.dll!System.Threading.Tasks.Task.ExecutionContextCallback(object obj)
mscorlib.dll!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx)
mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx)
mscorlib.dll!System.Threading.Tasks.Task.ExecuteWithThreadLocal(ref System.Threading.Tasks.Task currentTaskSlot = Id = 1131, Status = Running, Method = "Void <QueueAsynchronous>b__0(System.Threading.Tasks.Task)")
mscorlib.dll!System.Threading.Tasks.Task.ExecuteEntry(bool bPreventDoubleExecution)
mscorlib.dll!System.Threading.Tasks.Task.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()
mscorlib.dll!System.Threading.ThreadPoolWorkQueue.Dispatch()
mscorlib.dll!System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()
[Native to Managed Transition]
如果我将 JsonServiceClient 替换为对 System.Net.WebRequest 之类的异步调用(以检索和淡化 JSON 响应),我永远不会看到异常。
我试过 JsvServiceClient 也有同样的结果。我尝试使用 ConfigureAwait(false) 但没有成功。我已确保 web.config 文件正在调用:
<compilation targetFramework="4.5.2" debug="true" />
<httpRuntime targetFramework="4.5" />
我已经用以下代码包装了 Get 方法的主体:
await Task.Factory.StartNew(() =>
这解决了问题,但大大降低了服务的性能。吞吐量从能够在 2-3 秒内处理 100 个并发请求变为接近 20-40 秒。
我还能够在不遇到 NullReferenceException 的情况下进行异步数据库调用。
这绝对是 ServiceClient 的问题。任何帮助将不胜感激。谢谢!
使用 JsonHttpClient 代替 JsonServiceClient 解决了这个问题。
我有一个从上到下使用异步的 ServiceStack 服务。下面是一个简化的示例,所有层都折叠到服务定义。
public async Task<ReadItemResponse> Get(Dto.ReadItem request)
{
using (JsonServiceClient client = new JsonServiceClient("http://someserver/itemservice"))
{
ReadItemResponse response = await client.GetAsync(new ReadItem
{
ItemNumber = request.ItemNumber
});
return new Dto.ReadItemResponse
{
Item = new Dto.Item
{
ItemNumber = response.Item.ItemNumber,
ItemName = response.Item.ItemName
}
};
}
}
当我对服务进行大量并发调用时,上述代码会在 1 - 30 秒内在 System.Web 中引发 NullReferenceException。
System.Web.dll!System.Web.ThreadContext.AssociateWithCurrentThread(bool setImpersonationContext)
System.Web.dll!System.Web.HttpApplication.OnThreadEnterPrivate(bool setImpersonationContext)
System.Web.dll!System.Web.HttpApplication.System.Web.Util.ISyncContext.Enter()
System.Web.dll!System.Web.Util.SynchronizationHelper.SafeWrapCallback(System.Action action = {Method = {System.Reflection.RuntimeMethodInfo}})
System.Web.dll!System.Web.Util.SynchronizationHelper.QueueAsynchronous.AnonymousMethod__0(System.Threading.Tasks.Task _)
mscorlib.dll!System.Threading.Tasks.ContinuationTaskFromTask.InnerInvoke()
mscorlib.dll!System.Threading.Tasks.Task.Execute()
mscorlib.dll!System.Threading.Tasks.Task.ExecutionContextCallback(object obj)
mscorlib.dll!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx)
mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx)
mscorlib.dll!System.Threading.Tasks.Task.ExecuteWithThreadLocal(ref System.Threading.Tasks.Task currentTaskSlot = Id = 1131, Status = Running, Method = "Void <QueueAsynchronous>b__0(System.Threading.Tasks.Task)")
mscorlib.dll!System.Threading.Tasks.Task.ExecuteEntry(bool bPreventDoubleExecution)
mscorlib.dll!System.Threading.Tasks.Task.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()
mscorlib.dll!System.Threading.ThreadPoolWorkQueue.Dispatch()
mscorlib.dll!System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()
[Native to Managed Transition]
如果我将 JsonServiceClient 替换为对 System.Net.WebRequest 之类的异步调用(以检索和淡化 JSON 响应),我永远不会看到异常。
我试过 JsvServiceClient 也有同样的结果。我尝试使用 ConfigureAwait(false) 但没有成功。我已确保 web.config 文件正在调用:
<compilation targetFramework="4.5.2" debug="true" />
<httpRuntime targetFramework="4.5" />
我已经用以下代码包装了 Get 方法的主体:
await Task.Factory.StartNew(() =>
这解决了问题,但大大降低了服务的性能。吞吐量从能够在 2-3 秒内处理 100 个并发请求变为接近 20-40 秒。
我还能够在不遇到 NullReferenceException 的情况下进行异步数据库调用。
这绝对是 ServiceClient 的问题。任何帮助将不胜感激。谢谢!
使用 JsonHttpClient 代替 JsonServiceClient 解决了这个问题。