Skip to main content

Fixing Application Insights Dependency Injection After Upgrading Microsoft.ApplicationInsights.WorkerService to 3.0.0

As part of our routine monthly maintenance on Azure Functions, we update NuGet packages to stay current and pick up bug fixes. This month that process led to a breaking change when we upgraded Microsoft.ApplicationInsights.WorkerService from version 2.23.0 to 3.0.0 on our .NET 8 Azure Functions.

After the upgrade, our Application Insights logging stopped working entirely. Telemetry was no longer being captured, and it became clear that the dependency injection configuration in our Program.cs was the culprit. Here is what we had and how we fixed it.

The Problem

In version 2.23.0, we configured Application Insights in Program.cs like this:

public static void Main(string[] args)
{
    IHost host = new HostBuilder()
        .ConfigureFunctionsWorkerDefaults()
        .ConfigureServices(s => {
            s.AddApplicationInsightsTelemetryWorkerService(options =>
            {
                options.EnableAdaptiveSampling = false;
            });
            s.ConfigureFunctionsApplicationInsights();
        }).ConfigureLogging(logging =>
        {
            logging.Services.Configure<LoggerFilterOptions>(options =>
            {
                LoggerFilterRule? defaultRule = options.Rules.FirstOrDefault(rule => rule.ProviderName == "Microsoft.Extensions.Logging.ApplicationInsights.ApplicationInsightsLoggerProvider");
                if (defaultRule is not null)
                {
                    options.Rules.Remove(defaultRule);
                }
            });
            logging.AddApplicationInsights();
        })
        .Build();
    host.Run();
}

This worked fine under 2.23.0. After upgrading to 3.0.0, however, dependency injection for Application Insights broke. The EnableAdaptiveSampling option on AddApplicationInsightsTelemetryWorkerService no longer behaves the same way in version 3.0.0, and the logging.AddApplicationInsights() call in ConfigureLogging was no longer needed.

The Fix

After reviewing the breaking changes introduced in version 3.0.0, we updated our Program.cs to the following:

public static void Main(string[] args)
{
    IHost host = new HostBuilder()
        .ConfigureFunctionsWorkerDefaults()
        .ConfigureServices(s => {
            s.AddApplicationInsightsTelemetryWorkerService();
            s.ConfigureFunctionsApplicationInsights();
            s.Configure<TelemetryConfiguration>(config =>
            {
                config.SamplingRatio = 1;
            });
        }).ConfigureLogging(logging =>
        {
            logging.Services.Configure<LoggerFilterOptions>(options =>
            {
                LoggerFilterRule? defaultRule = options.Rules.FirstOrDefault(rule => rule.ProviderName == "Microsoft.Extensions.Logging.ApplicationInsights.ApplicationInsightsLoggerProvider");
                if (defaultRule is not null)
                {
                    options.Rules.Remove(defaultRule);
                }
            });
        })
        .Build();
    host.Run();
}

What Changed

There are three key differences between the old and new configuration:

1) Adaptive sampling is no longer configured on the service registration. In 2.23.0 we passed an options lambda to AddApplicationInsightsTelemetryWorkerService to disable adaptive sampling via EnableAdaptiveSampling = false. In 3.0.0 this option was removed from that registration. Sampling is now controlled directly on TelemetryConfiguration using the new SamplingRatio property. Setting SamplingRatio = 1 captures 100% of telemetry, which is the equivalent of disabling adaptive sampling.

2) logging.AddApplicationInsights() was removed. In 2.23.0 we explicitly added Application Insights to the logging pipeline inside ConfigureLogging. In 3.0.0 this is handled automatically by ConfigureFunctionsApplicationInsights(), making the explicit call redundant and in our case problematic.

3) Sampling configuration moved into ConfigureServices. The new pattern uses s.Configure<TelemetryConfiguration> inside ConfigureServices to set the sampling ratio, keeping all Application Insights setup in one place rather than split across ConfigureServices and ConfigureLogging.

Suggested Labels: Azure Functions, Microsoft Azure

If you run into this same issue after upgrading Microsoft.ApplicationInsights.WorkerService in your .NET 8 Azure Functions, hopefully this saves you some time tracking down the root cause.

Comments

Popular posts from this blog

Validating User Input In CRM Portals With JavaScript

When we are setting up CRM Portals to allow customers to update their information, open cases, fill out an applications, etc. We want to make sure that we are validating their input before it is committed to CRM.  This way we ensure that our data is clean and meaningful to us and the customer. CRM Portals already has a lot validation checks built into it. But, on occasion we need to add our own.  To do this we will use JavaScript to run the validation and also to output a message to the user to tell them there is an issue they need to fix. Before we can do any JavaScript, we need to check and see if we are using JavaScript on an Entity Form or Web Page.  This is because the JavaScript, while similar, will be different.  First, we will go over the JavaScript for Entity Forms.  Then, we will go over the JavaScript for Web Pages.  Finally, we will look at the notification JavaScript. Entity Form: if (window.jQuery) { (function ($) { if ...

Power Pages Update Last Successful Login Using JavaScript and Power Pages API

 Recently while working on a Power Pages implementation for a client, I had the requirement to show the last time a user logged in on their profile page.  I thought this would be easy to do as there is already a field on the contact record for "Last Successful Login" (      adx_identity_lastsuccessfullogin).  This use to update when a user logged in, but it appears Microsoft has removed that automation. While searching I came across a few different ways of achieving this task.  One used application insights in Azure and another one used an HTTP endpoint setup in Power Automate.  I thought, this needs to be simpler.  What I came up with is to use Liquid with JavaScript to tell if a user is logged in or not.  Then use the new Power Pages api to update the logged in users contact record to mark the last time they logged in. Here is the approach I setup: 1) Make sure you turn on the api for contact in Site Settings. 1) Link to Microsoft Do...

Reusable Method To Get Record By Id

I have a handful of reusable code that I use when creating plugins or external process (i.e. Azure Functions) for working with DataVerse. The first one I am providing is Getting a Record By Id: 1: private static Entity GetFullRecord(string entityName, string primaryKey, Guid recordId, IOrganizationService service) 2: { 3: using (OrganizationServiceContext context = new OrganizationServiceContext(service)) 4: { 5: return (from e in context.CreateQuery(entityName) 6: where (Guid)e[primaryKey] == recordId 7: select e).Single(); 8: } 9: } entityName = The logical name of the entity primaryKey = The primary key field for the entity. If using late binding you can create this dynamically by doing: $"{target.LogicalName}id" recordId = Guid of the record to get service = Service to interact with DataVerse