异步日志记录抛出NullReferenceException异常

11

我正在尝试在针对.NET 4.0的MVC 4控制器操作中使用AsyncTargetingPack将一些信息异步记录到SQL Server。 我本可以直接跳转到.NET 4.5,但我的应用程序位于Azure中,我们仍在等待更新...

这段代码按预期工作(一行被写入我的数据库而没有抛出异常):

public class SystemActionLogger : ISystemActionLogger
{
    private readonly ActionBlock<Tuple<SystemAction, object>> actionBlock;

    public SystemActionLogger(ISystemActionLogEntryRepository repository)
    {
        actionBlock = new ActionBlock<Tuple<SystemAction, object>>(
            entry => TaskEx.Run(async () =>
                {
                    string data = await JsonConvert.SerializeObjectAsync(entry.Item2);
                    await repository.PersistAsync(new SystemActionLogEntry(entry.Item1, data));
                }));
    }

    public void Log(SystemAction systemAction, object data)
    {
        actionBlock.Post(new Tuple<SystemAction, object>(systemAction, data));
    }
}

这段代码会抛出 NullReferenceException 异常:

public class SystemActionLogger : ISystemActionLogger
{
    private readonly ActionBlock<Tuple<SystemAction, object>> actionBlock;

    public SystemActionLogger(ISystemActionLogEntryRepository repository)
    {
        actionBlock = new ActionBlock<Tuple<SystemAction, object>>(async entry =>
            {
                string data = await JsonConvert.SerializeObjectAsync(entry.Item2);
                await repository.PersistAsync(new SystemActionLogEntry(entry.Item1, data));
            });
    }

    public void Log(SystemAction systemAction, object data)
    {
        actionBlock.Post(new Tuple<SystemAction, object>(systemAction, data));
    }
}

NullReferenceException: “对象引用未设置为对象的实例。”
Server stack trace: 
   at System.Web.ThreadContext.AssociateWithCurrentThread(Boolean setImpersonationContext)
   at System.Web.HttpApplication.OnThreadEnterPrivate(Boolean setImpersonationContext)
   at System.Web.LegacyAspNetSynchronizationContext.CallCallbackPossiblyUnderLock(SendOrPostCallback callback, Object state)
   at System.Web.LegacyAspNetSynchronizationContext.CallCallback(SendOrPostCallback callback, Object state)
   at System.Runtime.CompilerServices.TaskAwaiter.<>c__DisplayClassa.<OnCompletedInternal>b__0(Task param0)

Exception rethrown at [0]: 
   at System.Runtime.CompilerServices.AsyncMethodBuilderCore.<ThrowAsync>b__1(Object state)
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()
   at System.Threading.ThreadPoolWorkQueue.Dispatch()

我对异常没有任何可见性,因为它是所有外部代码。我不明白为什么第二段代码会失败。这是我最初编写的代码。

我做错了什么?


ASP.NET确实需要对async进行特殊支持,这是在.NET 4.5中添加的。我不建议在.NET 4.0的ASP.NET应用程序上尝试使用Async Targeting Pack - 一些简单的事情可能会起作用,但ASP.NET管道还没有准备好看到async代码。 - Stephen Cleary
1
您的堆栈跟踪包括对“LegacyAspNetSynchronizationContext”的引用,这是在.NET 4.5中添加的一种类型。您是否在Azure服务器上安装了.NET 4.5? - Stephen Cleary
嘿,史蒂芬,感谢您的回复。我曾在另一个 SO 帖子中看到过您类似的回答,并希望这不是事实,尤其是因为第一个代码块是有效的。关于类型,我在我的计算机上安装了 .NET 4.5,但我没有试图跳过障碍将其作为我的部署包的一部分上传到 Azure。这是一个有趣的观察。 - David Peden
我认为现在最好的选择就是等待。根据ScottGu的说法,Azure应该会在本月更新。与此同时,我正在使用AppHarbor,它几乎立即支持.NET 4.5。 - Stephen Cleary
是的,自从RTW以来,我一直在焦急地等待。我只是祈祷他们不会放弃基于角色的部署,因为他们似乎只谈论网站。我看到了@scottgu的帖子,也抱着希望...... - David Peden
3个回答

7

我刚刚遇到了一个非常相似的问题(在使用日志任务时从AssociateWithCurrentThread中出现NullReference)。

我的问题是原始操作没有等待日志记录任务完成,因此当日志完成并尝试重新加入原始线程时,会抛出nullReference异常,因为原始线程已终止。

对我来说,解决方法是确保请求控制器等待日志函数。


0

Dataflow 只能在 .NET 4.5 上运行。你正在使用 .NET 4.0 运行它是不受支持的,这很可能是你看到异常的原因。


-2

当我的 Web 服务以异步方式调用另一个 WCF 服务时,我在 .net4.5 中遇到了这个问题。 我只需添加一个短暂的定时 Wait(),因为我不关心响应(遥测事件)。

public static void Event(string key, string message) {
    Telemetry.Event(key, message).Wait(100);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接