Azure Functions and AppInsights RequestTelemetry - .net-core

I'm trying to enhance RequestTelemetry in AppInsights from HttpTrigger Azure Function v3.
Function is initialized with DI and Startup class.
[assembly: FunctionsStartup(typeof(Startup))]
namespace Hager.Example.FunctionApp.FunctionApp
{
public class Startup : FunctionsStartup
{
public override void Configure(IFunctionsHostBuilder builder)
{
// No service for repro
}
}
}
And my Function
public class Function1
{
private readonly ILogger _logger;
public Function1(ILogger<Function1> logger)
{
_logger = logger;
}
[FunctionName("HttpTriggered")]
public IActionResult Run(
[HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequestMessage req)
{
using var loggerScope = _logger.BeginScope("{InScope1}{InScope2}{InScope3}", Guid.NewGuid(), Guid.NewGuid(), Guid.NewGuid());
_logger.LogInformation("Started Execution");
_logger.LogWarning("With a custom property: {CustomProperty}.", Guid.NewGuid());
Activity.Current?.AddTag("TagStart", Guid.NewGuid());
if (Activity.Current == null)
{
// Always null
_logger.LogError("No ActivityCurrent {Activity}.", Activity.Current);
_logger.LogError("ActivityCurrent Tags {Activity}.", Activity.Current?.Tags);
}
// Activity.Current.AddTag("Tag2", Guid.NewGuid()); // <- NullException
_logger.LogInformation("Finished Execution");
return new NoContentResult();
}
}
My project packages:
<ItemGroup>
<PackageReference Include="Microsoft.ApplicationInsights" Version="2.17.0" />
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.17.0" />
<PackageReference Include="Microsoft.Azure.Functions.Extensions" Version="1.1.0" />
<PackageReference Include="Microsoft.NET.Sdk.Functions" Version="3.0.11" />
</ItemGroup>
Every logger and scopes are working as expected, but object ActivityTag is always null that shouldnt in Azure Functions.
Did I miss something?

Update:
Added Op's solution: by using request.HttpContext?.Features.Get<RequestTelemetry>(), it worked fine.
Please uninstall the 2 Application Insights packages: Microsoft.ApplicationInsights and Microsoft.ApplicationInsights.AspNetCore.
By default, Application Insights packages do not collect activity tags. So this should be the reason.
I tested your azure function without installing the above 2 Application Insights packages, it works well. Here is the screenshot of the test result:
Adding my local.settings.json here for your reference, the code is the same as yours:
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "xxxx",
"FUNCTIONS_WORKER_RUNTIME": "dotnet",
"APPINSIGHTS_INSTRUMENTATIONKEY": "xxx"
}
}
And if the 2 packages are necessary, maybe you can try add a custom ITelemetryInitializer by following this answer(btw, I didn't test it).

Related

Error java.exe exited with code 1 Xamarin Firbase Messaging

I am using nuget package Xamarin.Firebase.Messaging and Xamarin.GooglePlayServices.Baseto receive push notifications in my app, previously it was working fine, but when I update visual studio 2022 to 17.2.3 it stopped working
I Tried all of these:
Update all nuget packages
delete obj bin folder from all shared projects
enable multidex
install and include
<PackageReference Include="Xamarin.Google.Guava" ExcludeAssets="all"> <Version>27.1.0</Version> </PackageReference>
https://techhelpnotes.com/c-working-through-package-reference-errors-with-firebase-and-a-java-exe-exited-with-code-1-error-xamarin/
https://github.com/xamarin/GooglePlayServicesComponents/issues/379
and nothing i did before has worked
my code to receive push notifications:
using System;
using System.Threading.Tasks;
using Android.App;
using Firebase.Messaging;
using Plugin.DeviceInfo;
using Xamarin.Essentials;
using Xamarin.Forms;
namespace MyApp.Droid
{
[Service]
[IntentFilter(new[] { "com.google.firebase.MESSAGING_EVENT" })]
public class MyFirebaseMessagingService : FirebaseMessagingService
{
readonly AndroidNotificationManager _androidNotification = new AndroidNotificationManager();
public override void OnMessageReceived(RemoteMessage message)
{
var mensajeData = message.Data;
string title= mensajeData["notiTitle"];
string bodymessage= mensajeData["notiBody"];
_androidNotification.CreateLocalNotification(title, bodymessage);
}
public override void OnNewToken(string token)
{
base.OnNewToken(token);
Preferences.Set("TokenFirebase", token);
}
}
}
if I remove [Service] or
[IntentFilter(new[] { "com.google.firebase.MESSAGING_EVENT" })] the code compiles correctly
Apparently it was due to the update I made of visual studio because the android SDK was also updated, the solution was to edit [Services] to [Services(Exported = true)] for android +31, leaving the final code like this.
[Service(Exported = true)]
[IntentFilter(new[] { "com.google.firebase.MESSAGING_EVENT" })]
public class MyFirebaseMessagingService : FirebaseMessagingService
{
readonly AndroidNotificationManager _androidNotification = new AndroidNotificationManager();
public override void OnMessageReceived(RemoteMessage message)
{
var mensajeData = message.Data;
string title= mensajeData["notiTitle"];
string bodymessage= mensajeData["notiBody"];
_androidNotification.CreateLocalNotification(title, bodymessage);
}
public override void OnNewToken(string token)
{
base.OnNewToken(token);
Preferences.Set("TokenFirebase", token);
}
}
After adding that, everything compiled correctly
font answer
In addition to the answers here, I also had to export the broadcast reviver
[BroadcastReceiver(Enabled = true, Exported = true)]

Can't bind service implementation using DI inside function with ServiceBusTrigger parameter in .net core Azure Web Job

I have a .net core console application I am going to deploy as an Azure web job. The purpose of the job is to listen for new messages in an Azure Service Bus Queue. I have set the listener up using a function containing the [ServiceBusTrigger] Attribute. I built a dummy implementation which just reads the latest message from the queue - this works without issue - the message is passed correctly from the service bus queue to my function.
When I try to go to the next level and add an interface parameter to the function to be injected by DI I get an error.
Microsoft.Azure.WebJobs.Host.Indexers.FunctionIndexingException:
'Error indexing method 'Functions.ProcessMeasurementData''
InvalidOperationException: Cannot bind parameter 'service' to type
IProcessMeasurementService. Make sure the parameter Type is supported
by the binding. If you're using binding extensions (e.g. Azure
Storage, ServiceBus, Timers, etc.) make sure you've called the
registration method for the extension(s) in your startup code (e.g.
builder.AddAzureStorage(), builder.AddServiceBus(),
builder.AddTimers(), etc.).
This is my function. If I remove the parameter IProcessMeasurementService service it works with no issue running locally from Visual Studio 2019 (I haven't tried deploying to azure yet as a webjob), picking up new items as they are added to the Azure Service Bus Queue.
public class Functions
{
public static async Task ProcessMeasurementData(
[ServiceBusTrigger("process-measurement-data-queue", Connection = "AzureWebJobsServiceBus")] Message message,
IProcessMeasurementService service)
{
try
{
var measurements = JsonConvert
.DeserializeObject<List<CreateMeasurementInput>>
(Encoding.UTF8.GetString(message.Body));
await service.DoStuff(measurements);
// log.LogInformation(message.ContentType);
}
catch (Exception e)
{
throw;
}
}
I think I am registering the service correctly, like this:
{
// Register application services
services.AddSingleton<IProcessMeasurementService, ProcessMeasurementService>();
});
This is my main function in its entirety.
static void Main(string[] args)
{
var builder = new HostBuilder();
builder.ConfigureAppConfiguration((builder) =>
{
builder
.AddJsonFile("appsettings.json", false, true)
.AddEnvironmentVariables();
});
builder.ConfigureWebJobs(b =>
{
b.AddServiceBus(x =>
{
x.MessageHandlerOptions = new MessageHandlerOptions(ExceptionReceivedHandler)
{
AutoComplete = false
};
});
b.AddAzureStorageCoreServices();
});
builder.ConfigureServices(services =>
{
services.AddOptions();
// Register application services
services.AddSingleton<IProcessMeasurementService, ProcessMeasurementService>();
});
var host = builder.Build();
using (host)
{
host.Run();
}
}
From googling it feels like the problem might be something to do with my nuget package version. I tried adding a file called "host.json" in case it was a known problem with azure function versions conflicting with extensions libraries. But it did nothing. I am not actually using AzureFunctions (serverless functions I mean) but I am clutching at straws at this stage.
Does anyone know what the problem is?
This is the host.json just in case this is the issue.
{
"version": "2.0",
"extensionBundle": {
"id": "Microsoft.Azure.Functions.ExtensionBundle",
"version": "[1.*, 2.0.0)"
}
}
Here're my nuget versions installed
<PackageReference Include="Microsoft.Azure.ServiceBus" Version="4.1.2" />
<PackageReference Include="Microsoft.Azure.WebJobs" Version="3.0.16" />
<PackageReference Include="Microsoft.Azure.WebJobs.Extensions.ServiceBus" Version="4.1.1" />
<PackageReference Include="Microsoft.Azure.WebJobs.Sources" Version="3.0.16" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="2.2.0" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="2.2.0" />
Change from static function method to an instance member and inject the service via constructor injection directly into the function class.
public class Functions {
private readonly IProcessMeasurementService service;
public Functions (IProcessMeasurementService service) {
this.service = service;
}
public async Task ProcessMeasurementData(
[ServiceBusTrigger("process-measurement-data-queue", Connection = "AzureWebJobsServiceBus")] Message message)
{
try {
var measurements = JsonConvert
.DeserializeObject<List<CreateMeasurementInput>>
(Encoding.UTF8.GetString(message.Body));
await service.DoStuff(measurements);
// log.LogInformation(message.ContentType);
} catch (Exception e) {
//...
throw;
}
}
}

DotNet Core - Connection String from Class Library

I have my connection string to SQL stored in the Web project in appsettings.json
"ConnectionStrings": {
"MyDbConnectionString": "***"
},
Then I added a DB context using Scaffold
Scaffold-DbContext -Connection "name=MyDbConnectionString" -Provider "Microsoft.EntityFrameworkCore.SqlServer" ... -Force
I can use the context in a controller and I have no issues getting data or writing. However, I would like all my business logic to be on a separate class library. So here is my repository from my Library:
public class MyRepository
{
private static MyContext CurrentContext
{
get { return new MyContext(); }
}
public static async void AddEventLog(EventLog eventLog)
{
using (var context = CurrentContext)
{
context.EventLog.Add(eventLog);
await context.SaveChangesAsync();
}
}
}
But it fails when it tries to write to the DB.
System.InvalidOperationException: 'A named connection string was used, but the name 'MyDbConnectionString' was not found in the application's configuration.
Should I be adding appsettings.json to the library project (This seems redundant, and incorrect)? What am I missing? How do I reference back to the web projects appsettings.json file?
Any help would be greatly appreciated.
Here is my startup
services.AddDbContext<MyContext>(options =>options.UseSqlServer(Configuration.GetConnectionString("MyDbConnectionString")));
***** HERE ARE CHANGES I HAVE MADE TO THE WORK *****
I have found the issue I believe so here we go.
Remove the following from MySsdCaseContext.
public MySsdCaseContext()
{
}
and keep this one..
public MySsdCaseContext(DbContextOptions<MySsdCaseContext> options) : base(options)
{
}
For the purposes of fixing this comment out the following from OnConfiguring.
if (!optionsBuilder.IsConfigured)
{
optionsBuilder.UseSqlServer("name=MySsdCaseDb");
}
In startup.cs add the following inside ConfigureService method.
services.AddDbContext<MySsdCaseContext>(options
=>options.UseSqlServer(Configuration.GetConnectionString("MySsdCaseDb")));
This should prompt you to add a reference to MySsdCase.Core.Data class library. You don't currently have this. Basically put
the following at the top of startup.cs
using MySsdCase.Core.Data;
Ensure the following is inside MySsdCase.Web.cspoj
<ItemGroup>
<ProjectReference Include="..\MySsdCase.Core\MySsdCase.Core.csproj" />
</ItemGroup>
Do it like this...
public class EventLogRepository
{
private readonly MySsdCaseContext _context;
public async Task AddEventLogAsync(EventLog eventLog)
{
var myVar = await _context.Set<ClientDetails>()
.AsNoTracking()
.Select(p => p)
.Take(2)
.ToListAsync();
}
}
I think overall there was no reference to the DAL from the BL in startup.cs.

Asp.net web API CORS series/mysterious issue

I am facing a CORS policy problem and I do not know how to fix it. I tried many approaches but what makes me crazy is that the service works fine on some devices and I can utilize all its resources and works a little bit on others and does not work at others while the whole devices having the same configuration equally set. To be more clear I am having a Web application based entirely and only on AngularJS 2 and a Web API that exposes a few actions. I installed the IIS and hosted the Web API on the default Web Site, which means it can be called from port 80 for simplicity, and I hosted the Web application using port 4200. Now let's give more detail about my Web API application structure.
EMG.WebApi.Core -> this project is the core project in which I put the controller classes and the web configuration class
EMG.WebApi.WebHost -> this project is used merely for hosting and it contains a reference to the EMG.WebApi.Core project and is the one that contains the Global.asax and within its Application_Start I am calling the Register method of Configuration class of the WebApi.Core and give it as a parameter the GlobalConfiguration object to register my handlers, tracers etc.
using EMG.ElectrometerWS.WebApi.Core;
using System;
using System.Web.Http;
using EMG.ElectrometerWS.WebApi.Core.Configuration;
namespace EMG.ElectrometerWS.WebApi.WebHost
{
public class Global : System.Web.HttpApplication
{
protected void Application_Start(object sender, EventArgs e)
{
WebApiConfig.Register(GlobalConfiguration.Configuration);
GlobalConfiguration.Configuration.EnsureInitialized();
}
}
}
using EMG.ElectrometerWS.WebApi.Core.Handlers;
using EMG.ElectrometerWS.WebApi.Core.Tracer;
using System;
using System.Configuration;
using System.Web.Http;
using System.Web.Http.Cors;
using System.Web.Http.Tracing;
namespace EMG.ElectrometerWS.WebApi.Core.Configuration
{
public static class WebApiConfig
{
...
public static string CorsOrigin
{
get
{
string result =
ConfigurationManager.AppSettings.Get("CorsOrigin");
if (!string.IsNullOrEmpty(result))
{
return result;
}
throw new Exception("AppSetting CorsOrigin not found in
web.config file.");
}
}
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
EnableCorsAttribute enableCors =
new EnableCorsAttribute(CorsOrigin, "*", "*");
config.EnableCors(enableCors);
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
//config.Routes.MapHttpRoute(
// name: "Secret Api",
// routeTemplate: "secretapi/{controller}/{id}",
// defaults: new { id = RouteParameter.Optional },
// constraints: null,
// handler: new ApiKeyProtectionMessageHandler() {
// InnerHandler = new HttpControllerDispatcher(config)
// });
// Enable ASP.NET Web API tracing
//config.EnableSystemDiagnosticsTracing();
//config.Services.Replace(typeof(ITraceWriter), new
// EntryExitTracer());
//config.Services.Replace(typeof(ITraceWriter), new WebApiTracer());
//config.MessageHandlers.Add(new EmptyPostBodyMessageHandler());
// Message handler to check the performance in production
environment ONLY
config.MessageHandlers.Add(new TracingHandler());
//config.MessageHandlers.Add(new XHttpMethodOverrideHandler());
config.MessageHandlers.Add(new JwtHandler());
}
}
}
EMG.ElectrometerWS.WebApi.WebHost Web.Cofig
<appSettings>
....
<add key="CorsOrigin" value="http://localhost:4200"/>
</appSettings>
What makes me crazy is that everything works fine on my colleague laptop and he can use all the actions. On mine I cannot call some of PUT methods while I can for others on other colleague/testers they can only call GET methods!!! And increases my surprises is that after clearing the browser history/cookies one of those laptops that have only GET methods being called have all things works fine.
What I have tried:
First I added the below code as you can notice above to the configuration class
EnableCorsAttribute enableCors =
new EnableCorsAttribute(CorsOrigin, "*", "*");
config.EnableCors(enableCors);
Creating the following handler and registered it as the first handler before other handlers
public class CorsPreflightHandler : DelegatingHandler
{
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage
request,
CancellationToken cancellationToken)
{
if (request.Headers.Contains("Origin") && request.Method == HttpMethod.Options)
{
var response = new HttpResponseMessage(HttpStatusCode.OK);
response.Headers.Add("Access-Control-Allow-Origin", "*");
response.Headers.Add("Access-Control-Allow-Methods", "*");
return response;
}
return await base.SendAsync(request, cancellationToken);
}
}
Removing the previous code and configured the CORS using the Web.config file of the WebHost project
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="http:localhost:4200" />
<add name="Access-Control-Allow-Methods" value="*" />
<add name="Access-Control-Allow-Headers" value="*" />
</customHeaders>
</httpProtocol>
</system.webServer>
Finally removing the web config tags and enabled if on each controller class
[EnableCors(origins: "http://localhost:4200", headers: "*", methods: "*")]
public class XXXController : ApiController
{
Public string Get(int id)
{
return "value";
}
}
The CORS issue seems solved in meantime. I used the first approach by setting an application setting key/value for the allowed Origin then use that key/value to retrieve and register that Origin through a CORS attribute.
<appSettings>
....
<add key="CorsOrigin" value="http://localhost:4200"/>
</appSettings>
public static string CorsOrigin
{
get
{
string result =
ConfigurationManager.AppSettings.Get("CorsOrigin");
if (!string.IsNullOrEmpty(result))
{
return result;
}
throw new Exception("AppSetting CorsOrigin not found in web.config file.");
}
}
public static void Register(HttpConfiguration config)
{
....
EnableCorsAttribute enableCors =
new EnableCorsAttribute(CorsOrigin, "*", "*");
config.EnableCors(enableCors);
}
However, I still do not know what cause the problem from the beginning it may be an IIS issue or missing feature etc.

Nancy 500 server error with dotnetcore and kestrel

I am trying to use NancyFX (clint-eastwood) with dotnetcore1.1 and dotnet-cli 1.0.0-rc4-004771. My current project structure is -
CustomBootstrapper.cs
HomeModule.cs
index.sshtml
nancyapp.csproj
Program.cs
Startup.cs
And codes are -
nancyapp.csproj
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp1.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Owin">
<Version>1.1.0</Version>
</PackageReference>
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel">
<Version>1.1.0</Version>
</PackageReference>
<PackageReference Include="Nancy">
<Version>2.0.0-clinteastwood</Version>
</PackageReference>
</ItemGroup>
</Project>
Program.cs
using System.IO;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
namespace nancyapp
{
class Program
{
static void Main(string[] args)
{
var host = new WebHostBuilder()
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseStartup<Startup>()
.Build();
host.Run();
}
}
}
Startup.cs
using Microsoft.AspNetCore.Builder;
using Nancy.Owin;
namespace nancyapp
{
public class Startup
{
public void Configure(IApplicationBuilder app)
{
app.UseOwin(x => x.UseNancy());
}
}
}
HomeModule.cs
using Nancy;
namespace nancyapp
{
public class HomeModule : NancyModule
{
public HomeModule()
{
Get("/", _ => { return View["index.sshtml"]; });
Get("/test/{name}", args => new Person() { Name = args.name });
}
}
public class Person
{
public string Name { get; set; }
}
}
index.sshtml
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
Welcome to Nancy App.
</body>
</html>
CustomBootstrapper.cs is currently empty.
When I try to access Get("/test/{name}", args => new Person() { Name = args.name }); from a rest client i get the expected result.
However, when I try to access to root or Get("/", _ => { return View["index.sshtml"]; });, I get a 500 server error saying -
Error details are currently disabled. To enable it, please set
TraceConfiguration.DisplayErrorTraces to true. For example by
overriding your Bootstrapper's Configure method and calling
environment.Tracing(enabled: false, displayErrorTraces: true)
I tried following the instruction in the error message and enable error tracing by including the following code in CustomBootstrapper.cs
protected override void ApplicationStartup(Nancy.TinyIoc.TinyIoCContainer container, IPipelines pipelines)
{
var environment = GetEnvironment();
environment.Tracing(true, true);
}
But then I get the following error when trying to run the application with dotnet run
Unhandled Exception: System.ArgumentException: An item with the same
key has already been added. Key: Nancy.TraceConfiguration at
System.ThrowHelper.ThrowAddingDuplicateWithKeyArgumentException(Object key) at
System.Collections.Generic.Dictionary`2.Insert(TKey key,TValue value, Boolean add) at
nancyapp.CustomBootstrapper.ApplicationStartup(TinyIoCContainer container, IPipelines pipelines) in D:\TempWork\nancyapp\CustomBootstrapper.cs:line 17 at
Nancy.Bootstrapper.NancyBootstrapperBase`1.Initialise() at
Nancy.Owin.NancyMiddleware.UseNancy(NancyOptions options) at
Nancy.Owin.DelegateExtensions.UseNancy(Action`1 builder, NancyOptionsoptions) at
nancyapp.Startup.<>c.<Configure>b__0_0(Action`1 x) in D:\TempWork\nancyapp\Startup.cs:line 10 at
Microsoft.AspNetCore.Builder.OwinExtensions.UseOwin(IApplicationBuilder builder, Action`1 pipeline) at
nancyapp.Startup.Configure(IApplicationBuilder app) in D:\TempWork\nancyapp\Startup.cs:line 10
--- End of stack trace from previous location where exception was thrown --- at
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at
Microsoft.AspNetCore.Hosting.ConventionBasedStartup.Configure(IApplicationBuilder app) at
Microsoft.AspNetCore.Hosting.Internal.WebHost.BuildApplication() at
Microsoft.AspNetCore.Hosting.WebHostBuilder.Build() at
nancyapp.Program.Main(String[] args) in D:\TempWork\nancyapp\Program.cs:line 11
I am not sure what's causing the error or how to enable tracing. Can anyone help?
The are two problems here :
The 500 is because the view was not found , what you need to do is provide a root path by implementing IRootPathProvider and return Directory.GetCurrent().
Secondly to enable tracing you need public override void Configure(INancyEnvironment environment) this adds the keys hence you the exception you are getting.
You may get the same server error (500) when using Nancy in a .NET Core 3.1 app in combination with Owin >= v3.
I've solved the issue by downgrading Microsoft.AspNetCore.Owin from v3.x to v2.2.0.
My running setup was the following after the downgrade:
It's also fine to return a simple text for testing:
Get("/", _ => { return new TextResponse(HttpStatusCode.OK, "Hello world!"); });

Resources