Async logging throwing a NullReferenceException
Asked Answered
E

3

11

I am trying to asynchronously log some information to SQL Server inside of an MVC 4 controller action targeting .NET 4.0 using the AsyncTargetingPack. I would jump straight to .NET 4.5 but my app lives in Azure and we're still waiting for the update...

This code works as expected (a row is written to my database with no exceptions thrown):

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));
    }
}

And this code throws a 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: "Object reference not set to an instance of an object."

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()

I have no visibility into the exception as it is all external code. I don't understand why the second block of code fails. This is the code I originally wrote.

What am I doing wrong?

Egeria answered 19/10, 2012 at 7:6 Comment(5)
ASP.NET does need special support for async, which was added in .NET 4.5. I would not try using the Async Targeting Pack on ASP.NET apps for .NET 4.0 - a few simple things would work but the ASP.NET pipeline is just not ready to see async code.Uttasta
Your stack trace includes a reference to LegacyAspNetSynchronizationContext, a type added in .NET 4.5. Did you install .NET 4.5 on your Azure server?Uttasta
Hey Stephen, thanks for the reply. I had seen a similar response from you on another SO post and was hoping that this was not the case, especially since the first block of code works. Regarding the type, I have .NET 4.5 installed on my box but I did not attempt to jump through hoops and make it a part of my deployment package to Azure. That's an interesting observation.Egeria
I think the best option now is to just wait. Azure should be updated this month according to ScottGu. In the meantime, I'm using AppHarbor, which had .NET 4.5 support almost immediately.Uttasta
Yep, I've been anxiously waiting ever since RTW. I'm just crossing my fingers that they don't leave the roles-based deployments behind since they only seem to be talking about websites. I did see @scottgu's post and have my fingers crossed...Egeria
S
7

I was just having a very similar issue (NullReference from AssociateWithCurrentThread when using a logging task).

The issue I was having was that the original action did not await the completion of the logging task, so when the log finishes and tries to rejoin the original thread a nullReference is thrown because the original thread has terminated.

This was solved for me by making sure that the request controller awaited the logging function.

Seicento answered 17/5, 2013 at 18:52 Comment(0)
C
0

Dataflow only works on .NET 4.5. The fact that you're running it on .NET 4.0 is unsupported and is likely why you're seeing spurious exceptions.

Cyprinid answered 31/12, 2012 at 17:32 Comment(0)
F
-2

I had this problem with .net4.5 when my web service was invoking another WCF service in an async manner. I simply appended a short timed Wait() as I didn't care about the response (telemetry event).

public static void Event(string key, string message) {
    Telemetry.Event(key, message).Wait(100);
}
Flagelliform answered 6/6, 2014 at 23:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.