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, 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):

  • ExecuteReaderAsync
  • ExecuteNonQueryAsync
  • ExecuteScalarAsync
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.

Instrumented async methods must have return type of Task or Task<T>, not void

The .NET agent does not support instrumentation of async methods that have return type of anything other than Task or Task<T>. The agent does not support async void methods.

For more information, refer to the Microsoft documentation about async return types:

No instrumentation for begin* and end* style

The .NET agent does not instrument any .NET methods that 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 capture scoped metrics or 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

Recommendations for learning more: