Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use dependency inject for TelemetryConfiguration in Azure Function

I try to use Dependency injection in Azure Functions for TelemetryConfiguration. In my function I will have it resolved when I inject TelemetryConfiguration in the functions constructor. I suppose I don't really understand how I will do with TelemetryConfiguration in StartUp, thats why I get an exception. How will I add the TelemetryConfiguration I already configured.

I have did an easy example here what I'm doing so far.

[assembly: FunctionsStartup(typeof(StartUp))]
public class StartUp : FunctionsStartup
{
    private string OmsModule { get; } = "OMS.VA";

    public override void Configure(IFunctionsHostBuilder builder)
    {
        builder.Services.Configure<TelemetryConfiguration>(
            (o) =>
            {
                o.InstrumentationKey = Environment.GetEnvironmentVariable("APPINSIGHTS_INSTRUMENTATIONKEY");
                o.TelemetryInitializers.Add(new OperationCorrelationTelemetryInitializer());
            });
    }
}

public class StopPlaceUpdateTimerTrigger
{
    private TelemetryClient _telemetryClient;
    private string _azureWebJobsStorage;

    public StopPlaceUpdateTimerTrigger(TelemetryConfiguration telemetryConfiguration)
    {
        _telemetryClient = new TelemetryClient(telemetryConfiguration);
    }

    [FunctionName("StopPlaceLoader")]
    public async Task StopPlaceLoaderMain([TimerTrigger("%CRON_EXPRESSION%", RunOnStartup = true)]TimerInfo myTimerInfo, ILogger log, ExecutionContext context)
    {
        SetConfig(context);
        var cloudTable = await GetCloudTableAsync();
        if (cloudTable == null)
        {
            //Do nothing
        }
        //Do nothing
    }

    private async Task<CloudTable> GetCloudTableAsync()
    {
        var storageAccount = CloudStorageAccount.Parse(_azureWebJobsStorage);
        var tableClient = storageAccount.CreateCloudTableClient();
        var table = tableClient.GetTableReference(nameof(StopPlaceLoaderCacheRecord));

        if (!await table.ExistsAsync())
        {
            await table.CreateIfNotExistsAsync();
        }
        return table;
    }

    private void SetConfig(ExecutionContext context)
    {
        var config = new ConfigurationBuilder()
            .SetBasePath(context.FunctionAppDirectory)
            .AddJsonFile("local.settings.json", optional: true)
            .AddEnvironmentVariables()
            .Build();
        _azureWebJobsStorage = config["AzureWebJobsStorage"];
    }
}


//local.settings.json
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "DefaultEndpointsProtocol...",
"FUNCTIONS_WORKER_RUNTIME": "dotnet",
"EnableMSDeployAppOffline": "True",
    "CRON_EXPRESSION": "0 */5 22-3 * * *",
"APPINSIGHTS_INSTRUMENTATIONKEY": "..."
  }
}

I get the following Exception; Microsoft.Extensions.DependencyInjection.Abstractions: Unable to resolve service for type 'Microsoft.ApplicationInsights.Extensibility.TelemetryConfiguration' while attempting to activate 'OMS.VA.RealTime.StopPlaceLoader.StopPlaceUpdateTimerTrigger'.

like image 743
Roger Uhlin Avatar asked Oct 15 '19 14:10

Roger Uhlin


People also ask

What is IServiceCollection in .NET core?

IServiceCollection is the collection of the service descriptors. We can register our services in this collection with different lifestyles (Transient, scoped, singleton) IServiceProvider is the simple built-in container that is included in ASP.NET Core that supports constructor injection by default.


2 Answers

Update:

We can change this line of code var newConfig = TelemetryConfiguration.Active; to var newConfig = TelemetryConfiguration.CreateDefault(); , since TelemetryConfiguration.Active is deprecated.


Please use the code below for TelemetryConfiguration DI, I test it with a blob trigger function and works well:

using System.IO;
using System.Linq;
using Microsoft.ApplicationInsights;
using Microsoft.ApplicationInsights.Extensibility;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;

[assembly: WebJobsStartup(typeof(FunctionApp17.MyStartup))]
namespace FunctionApp17
{

    public class MyStartup : IWebJobsStartup
    {
        public void Configure(IWebJobsBuilder builder)
        {
            var configDescriptor = builder.Services.SingleOrDefault(tc => tc.ServiceType == typeof(TelemetryConfiguration));
            if (configDescriptor?.ImplementationFactory != null)
            {
                var implFactory = configDescriptor.ImplementationFactory;
                builder.Services.Remove(configDescriptor);
                builder.Services.AddSingleton(provider =>
                {
                    if (implFactory.Invoke(provider) is TelemetryConfiguration config)
                    {
                        var newConfig = TelemetryConfiguration.Active;
                        newConfig.ApplicationIdProvider = config.ApplicationIdProvider;
                        newConfig.InstrumentationKey = config.InstrumentationKey;

                        return newConfig;
                    }
                    return null;
                });
            }
        }
    }

    public class Function1
    {
        private TelemetryClient _telemetryClient;

        public Function1(TelemetryConfiguration telemetryConfiguration)
        {
            _telemetryClient = new TelemetryClient(telemetryConfiguration);
        }

        [FunctionName("Function1")]
        public void Run([BlobTrigger("samples-workitems/{name}", Connection = "AzureWebJobsStorage")]Stream myBlob, string name, ILogger log)
        {
            log.LogInformation($"!!!!!!!!!! C# Blob trigger function Processed blob\n Name:{name} \n Size: {myBlob.Length} Bytes");
            _telemetryClient.TrackTrace("this is a test message from DI of telemetry client !!!!!!!!!!!!!!");
        }
    }
}

the test result as below, I can see the logs in the application insights in azure portal:

enter image description here

And one more thing, I see you try to use ITelemetry Initializer in your code. You can follow this GitHub issue for your ITelemetry Initializer or Itelemetry Processor

like image 65
Ivan Yang Avatar answered Oct 08 '22 23:10

Ivan Yang


If you use builder.Services.Configure<TelemetryConfiguration>() to configure, you are using Options pattern in ASP.NET Core.

To access the option, you need to do as following:

public StopPlaceUpdateTimerTrigger(IOptionsMonitor<TelemetryConfiguration> telemetryConfiguration)
{
    _telemetryClient = new TelemetryClient(telemetryConfiguration.CurrentValue);
}

If you just want to directly use TelemetryConfiguration object, you need to add it in service collection:

builder.Services.AddSingleton<TelemetryConfiguration >(sp =>
{
    var telemetryConfiguration = new TelemetryConfiguration();
    telemetryConfiguration.InstrumentationKey = Environment.GetEnvironmentVariable("APPINSIGHTS_INSTRUMENTATIONKEY");
    telemetryConfiguration.TelemetryInitializers.Add(new OperationCorrelationTelemetryInitializer());
    return telemetryConfiguration;
}

Then you can :

public StopPlaceUpdateTimerTrigger(TelemetryConfiguration telemetryConfiguration)
{
    _telemetryClient = new TelemetryClient(telemetryConfiguration);
}

Hope it helps.

like image 27
Jack Jia Avatar answered Oct 08 '22 23:10

Jack Jia