Async support in .NET

New Relic's .NET agent automatically includes asynchronous framework instrumentation as of agent version 6.0. With the standard async-await pattern, as introduced in .NET 4.5, calls to async methods can return even though the work being done in the called method is still in progress. The .NET agent observes this in-progress asynchronous work and waits for it to complete before recording timings.

Features supporting async instrumentation

With the addition of async support, new features are available in New Relic's .NET agent. However as part of this enhancement, a small number of features previously provided by the agent currently are not available. Except as noted, the agent does not instrument async methods for any of the other supported frameworks for the .NET agent.

HttpClient async methods

The agent instruments these HttpClient async methods:

  • SendAsync
  • GetAsync
  • PostAsync
  • PutAsync
  • DeleteAsync
  • GetStringAsync
  • GetStreamAsync
  • GetByteArrayAsync
RestClient async methods

The agent instruments these RestClient async methods:

  • ExecuteTaskAsync
  • ExecuteGetTaskAsync
  • ExecutePostTaskAsync
SqlCommand async methods

The agent instruments these SqlCommand async methods:

  • ExecuteReaderAsync
  • ExecuteNonQueryAsync
  • ExecuteScalarAsync
  • ExecuteXmlReaderAsync
SqlDataReader async methods

The agent instruments these SqlDataReader async methods:

  • NextResultAsync
  • ReadAsync
NpgsqlCommand async methods (Postgres)

The agent instruments these NpgsqlCommand async methods (Postgres):

  • ExecuteAsync
Custom instrumentation

The .NET agent supports custom instrumentation of your own async methods.

Known limitations

Here is a summary of known limitations for async instrumentation with New Relic's .NET agent.

Requires updated ASP pipeline

The .NET agent will not instrument async methods if the legacy ASP pipeline is present. Since Microsoft replaced the legacy ASP pipeline well before async methods were introduced, this issue typically only affects applications created under .NET Framework 4.0 or lower, then migrated to .NET Framework 4.5 or higher. To see if this issue affects your application, and how to resolve it if it does, review the troubleshooting procedures.

No instrumentation for begin* and end* style

The .NET agent does not currently instrument any .NET methods which use the begin* and end* style. If your application calls these types of methods, no segments will be created for them. However, the rest of your transactions and segments will be created correctly.

No capture of scoped metrics/segments in manually created threads

The .NET agent does not currently capture scoped metrics/segments within threads that are manually created by your application.

For instrumented async methods, use await, not Task.Result()

If your application calls instrumented async methods, use await rather than Task related methods like Task.Result() to wait for the results. Otherwise, instrumentation may not work properly.

In general, avoid using Task.Result() when calling async methods. It can lead to deadlocks.

ContinueWith({}) block may affect timing measurements

If you add your own ContinueWith({}) block to the promise returned by an instrumented async method, it may affect timing measurements reported by the instrumentation. For example, the time may include the time your ContinueWith takes to execute.

Problem with nesting in IIS-hosted WCF apps

IIS-hosted WCF services do not properly nest the WCF segment under the ExecuteRequestHandler segment. The two segments will appear to be siblings within a transaction trace, even though their reported total time will be accurate.

Async methods in self-hosted WCF services require custom instrumentation

Top-level OperationContract methods in self-hosted WCF services will not create transactions and segments unless you add explicit custom instrumentation to your service.

Use this instrumentation as your tracerFactory:

tracerFactory name="NewRelic.Providers.Wrapper.CustomInstrumentationAsync.OtherTransactionWrapperAsync"

Then reference the async methods in your service.

Segments don't auto-create stack traces

Segments in a transaction trace will not generate stack traces automatically, even if they run longer than transaction_tracer.stack_trace_threshold.

For more help

Additional documentation resources include:

  • Response time (understanding response time vs. total time with a synchronous or asynchronous computing model)
  • Missing async metrics (troubleshooting procedures for apps created under .NET Framework 4.0 or lower, then migrated to .NET Framework 4.5 or higher)
  • Upgrade the .NET agent (procedures for upgrading the agent)

Recommendations for learning more: