Application insight not receiving Nlog for hosted service - azure-application-insights

I try everything I can think of but I must miss something.
I have a hostedService project in netcoreapp3.1
I referenced the following
<PackageReference Include="Microsoft.ApplicationInsights.NLogTarget" Version="2.20.0" />
<PackageReference Include="Microsoft.ApplicationInsights.WorkerService" Version="2.20.0" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="3.1.10" />
<PackageReference Include="NLog" Version="4.7.15" />
<PackageReference Include="NLog.Extensions.Logging" Version="1.7.4" />
my appsetting is as follow
{
"Logging": {
"LogLevel": {
"Default": "Warning",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Warning"
},
"ApplicationInsights": {
"LogLevel": {
"Default": "Warning",
"WorkerServiceTestLog": "Debug"
}
}
},
"ApplicationInsights": {
"InstrumentationKey": "XXX"
}
}
The nlog config look like that
<extensions>
<add assembly="Microsoft.ApplicationInsights.NLogTarget" />
</extensions>
<targets>
<target type="ApplicationInsightsTarget" name="aiTarget" >
</target>
<target type="Console" name="consolelog"/>
<target type="Debugger" name="debuglog" />
</targets>
<rules>
<logger name="*" minlevel="Debug" writeTo="debuglog" />
<logger name="*" minlevel="Debug" writeTo="consolelog" />
<logger name="*" minlevel="Debug" writeTo="aiTarget" />
</rules>
I build the host like that
var config = new ConfigurationBuilder()
.SetBasePath(System.IO.Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.Build();
return Host.CreateDefaultBuilder(args)
.ConfigureLogging(logging =>
{
logging.ClearProviders();
logging.AddNLog(config);
})
.ConfigureServices((hostContext, services) =>
{
services.AddHostedService<Worker>();
services.AddApplicationInsightsTelemetryWorkerService();
});
The worker simply test the logs
public class Worker : BackgroundService
{
private readonly NLog.ILogger _nlogger = LogManager.GetCurrentClassLogger();
private readonly ILogger<Worker> _logger;
public Worker(ILogger<Worker> logger)
{
_logger = logger;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
for (var i = 0; i < 10; i++)
{
_logger.LogError("Microsoft Logging:Error");
_logger.LogInformation("Microsoft Logging:Information");
_nlogger.Error("NLOG:Error");
_nlogger.Info("NLOG:Information");
await Task.Delay(2000, stoppingToken);
}
}
}
Now I have all log information in the console and debugger as excepted
But only the log from Microsoft extension is going in application insight
What am I missing there?

Follow the workaround to fix the issue:
Startup.cs
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages();
services.AddApplicationInsightsTelemetry(Configuration["APPLICATIONINSIGHTS_CONNECTION_STRING"]);
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILogger<Startup> logger)
{
logger.LogInformation(
"Configuring for {Environment} environment",
env.EnvironmentName);
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
});
}
}
Program.cs
public class Program
{
public static void Main(string[] args)
{
// Setting up the Nlog
var logger = LogManager.Setup()
.LoadConfigurationFromAppSettings()
.GetCurrentClassLogger();
try
{
logger.Debug("Nlog Log: init main");
CreateHostBuilder(args).Build().Run();
}
catch (Exception exception)
{
//NLog: catch setup errors
logger.Error(exception, " Nlog Log:Stopped program because of exception");
throw;
}
finally
{
// Ensure to flush and stop internal timers/threads before application-exit (Avoid segmentation fault on Linux)
NLog.LogManager.Shutdown();
}
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
})
//Configuring the Nlog
.ConfigureLogging(logging =>
{
logging.ClearProviders();
logging.SetMinimumLevel(Microsoft.Extensions.Logging.LogLevel.Trace);
})
.UseNLog()
//Calling the Host Services (Worker)
.ConfigureServices((hostContext, services) =>
{
services.AddHostedService<Worker>();
});
}
Here is my worker.cs
private readonly NLog.ILogger _nlogger = LogManager.Setup()
.LoadConfigurationFromAppSettings()
.GetCurrentClassLogger();
private readonly ILogger<Worker> _logger;
public Worker(ILogger<Worker> logger)
{
_logger = logger;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
for (var i = 0; i < 10; i++)
{
_logger.LogError("Microsoft Logging:Error Iteration:" + i);
_logger.LogInformation("Microsoft Logging:Information Iteration:" + i);
_nlogger.Error("NLOG:Error Iteration:"+i);
_nlogger.Info("NLOG:Information Iteration:" + i);
await Task.Delay(2000, stoppingToken);
}
}
Result in Application Insights
Updated Answer:
Here you can see the Application Insights connection string get from secrect.json

Related

How to get Blazor HotReload to work with Startup class

I have a Blazor WebAssembly app which is hosted by a .net Core app. I've been upgrading it from .net 6.0 and was using a Startup class to initialize the server app
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args)
.Build()
.Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureHostConfiguration(conf =>
{
conf.AddJsonFile($"appsettings.{Environment.MachineName}.json", optional: true, reloadOnChange: true);
})
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
public class Startup
{
public Startup(IConfiguration configuration, IWebHostEnvironment environment)
{
Configuration = configuration;
WebHostEnvironment = environment;
}
public IConfiguration Configuration { get; }
public IWebHostEnvironment WebHostEnvironment { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
services.AddRazorPages();
/*Other services registered here*/
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
// Configure the HTTP request pipeline.
if (env.IsDevelopment())
{
app.UseWebAssemblyDebugging();
}
else
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseBlazorFrameworkFiles();
app.UseStaticFiles();
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
endpoints.MapControllers();
endpoints.MapFallbackToFile("index.html");
});
}
}
Now when I run this app, I can't get hot reloading of Blazor or CSS at all.
What I've found is that if I use the newer pattern implementing WebApplication.CreateBuilder, hot reloading works.
public static void Main(string[] args)
{
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllersWithViews();
builder.Services.AddRazorPages();
ConfigureServices(builder.Services, builder.Configuration);
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseWebAssemblyDebugging();
}
else
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseBlazorFrameworkFiles();
app.UseStaticFiles();
var imagesPhysicalPath = app.Configuration.GetSection("ImagesDirectoryPath").Get<string>(); ;
app.UseStaticFiles();
app.UseStaticFiles(new StaticFileOptions
{
RequestPath = "/product-images",
FileProvider = new PhysicalFileProvider(imagesPhysicalPath)
});
app.UseRouting();
app.MapRazorPages();
app.MapControllers();
app.MapFallbackToFile("index.html");
app.Run();
}
I marginally prefer the former version as it allows me to customise the Configuration mechanism.
Can anyone tell me what I'm missing in the original setup that might have broken the hot reload process?

IHttpContextAccessor.HttpContext is null

I'm using DotNet 5.0, and even though I register HttpContextAccessor in the Startup.ConfigureServices whenever I try to reach it inside the code, IHttpContextAccessor.HttpContext is always null.
This is my Startup.cs file's ConfigureServices Method
public void ConfigureServices(IServiceCollection services)
{
container.Options.DefaultScopedLifestyle = new AsyncScopedLifestyle();
var environmentName = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
this.Configuration = new ConfigurationBuilder().SetBasePath(System.IO.Directory.GetCurrentDirectory()).AddJsonFile($"appsettings.{environmentName}.json").Build();
services.AddControllers();
services.AddSimpleInjector(container, options =>
{
options.AddAspNetCore();
});
services.AddHttpContextAccessor();
}
And this is the Configure method of the same file:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseForwardedHeaders(new ForwardedHeadersOptions
{
ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
});
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
app.UseSimpleInjector(container);
container.Verify();
}
And also I'm using hangfire, but whenever a job gets triggered I cannot reach HttpContextAccessor through dependency injection. It is always null.
For example this is one of my business layer files:
public class FooService
{
private readonly IHttpContextAccessor _httpContextAccessor;
public FooService(IHttpContextAccessor httpContextAcessor)
{
_httpContextAccessor = httpContextAccessor;
}
public DoSomething()
{
var tryoutVar = _httpContextAccessor.HttpContext;
}
}
The tryoutVar variable is set to null, always.
Why is this happening?

Call a Hub in another class

I get an error of:
System.InvalidOperationException: 'Unable to resolve service for type 'Microsoft.AspNetCore.SignalR.IHubContext`1[Common.RfidHub]' while attempting to activate 'Rfid.RfidEngine'.'
on the part of var rfidEngine = serviceProvider.GetService<IRfidEngine>();
I have this code:
Start
public void ConfigureServices(IServiceCollection services)
{
services.AddSignalR();
var collection = new ServiceCollection();
collection.AddScoped<IApplicationLogger, ApplicationLogger>();
collection.AddScoped<IRfidEngine, RfidEngine>();
IServiceProvider serviceProvider = collection.BuildServiceProvider();
var applicationLogger = serviceProvider.GetService<IApplicationLogger>();
applicationLogger.LoggingSettings = applicationSetting.LoggingSetting;
var signalR = serviceProvider.GetService<IHubContext<RfidHub>>();
var applicationLogger = serviceProvider.GetService<IApplicationLogger>();
applicationLogger.LoggingSettings = applicationSetting.LoggingSetting;
var rfidEngine = serviceProvider.GetService<IRfidEngine>();
rfidEngine.Start();
applicationLogger.LogInformation($#"Program has started", LoggerType.Console);
}
public void Configure(IApplicationBuilder app)
{
app.UseCors("ApplicationCors");
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapHub<RfidHub>("/rfidhub");
});
}
Hub
public class RfidHub : Hub
{
public async Task SendReadings(string user, string message)
{
await Clients.All.SendAsync("ReceiveReading", user, message);
}
}
RfidEngine
public class RfidEngine : IDisposable, IRfidEngine
{
public RfidEngine(IApplicationLogger applicationLogger, IHubContext<RfidHub> hubContext)
{
this.applicationLogger = applicationLogger;
this.hubContext = hubContext;
}
private void SendViaHub(string message)
{
hubContext.Clients.All.SendAsync("ReceiveReadings", message);
}
}
This is my version of Signalr:
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="5.0.8" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="5.0.2" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
</ItemGroup>
I need to be able to call the HubContext on a different class. What can I try to resolve this?

.net core 3.1 HostBuilder not having RunAsServiceAsync method (IHostBuilder does not contain definition for RunAsServiceAsync)

I have .net core 3.1 console application and I want to run it as a windows service, my program.cs looks like
public class Program
{
public static async Task Main(string[] args)
{
var isService = !(Debugger.IsAttached || args.Contains("--console"));
var builder = CreateHostBuilder(args);
if (isService)
{
await builder.RunAsServiceAsync();
}
else
{
await builder.RunConsoleAsync();
}
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.UseWindowsService()
.ConfigureServices((hostContext, services) =>
{
services.AddHostedService<Worker1>();
services.AddHostedService<Worker2>();
});
}
and the .csproj is
<Project Sdk="Microsoft.NET.Sdk.Worker">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<UserSecretsId>dotnet-MyWorkerService-16487890-DF99-45C2-8DC4-5475A21D6B75</UserSecretsId>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Hosting" Version="3.1.16" />
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="3.1.16" />
</ItemGroup>
</Project>
but for RunAsServiceAsync() error is coming like "IHostBuilder does not contain definition for RunAsServiceAsync"
Can anyone please point to me where / what I am missing?
RunAsServiceAsync appears to be 3rd party extension on IHostBuilder.
It does not appear to be a built in function, native to .NET Core.
I found an old implementation on GitHub here that you could probably implement yourself
public static class ServiceBaseLifetimeHostExtensions
{
public static IHostBuilder UseServiceBaseLifetime(this IHostBuilder hostBuilder)
{
return hostBuilder.ConfigureServices((hostContext, services) => services.AddSingleton<IHostLifetime, ServiceBaseLifetime>());
}
public static Task RunAsServiceAsync(this IHostBuilder hostBuilder, CancellationToken cancellationToken = default)
{
return hostBuilder.UseServiceBaseLifetime().Build().RunAsync(cancellationToken);
}
}
public class ServiceBaseLifetime : ServiceBase, IHostLifetime
{
private TaskCompletionSource<object> _delayStart = new TaskCompletionSource<object>();
public ServiceBaseLifetime(IApplicationLifetime applicationLifetime)
{
ApplicationLifetime = applicationLifetime ?? throw new ArgumentNullException(nameof(applicationLifetime));
}
private IApplicationLifetime ApplicationLifetime { get; }
public Task WaitForStartAsync(CancellationToken cancellationToken)
{
cancellationToken.Register(() => _delayStart.TrySetCanceled());
ApplicationLifetime.ApplicationStopping.Register(Stop);
new Thread(Run).Start(); // Otherwise this would block and prevent IHost.StartAsync from finishing.
return _delayStart.Task;
}
private void Run()
{
try
{
Run(this); // This blocks until the service is stopped.
_delayStart.TrySetException(new InvalidOperationException("Stopped without starting"));
}
catch (Exception ex)
{
_delayStart.TrySetException(ex);
}
}
public Task StopAsync(CancellationToken cancellationToken)
{
Stop();
return Task.CompletedTask;
}
// Called by base.Run when the service is ready to start.
protected override void OnStart(string[] args)
{
_delayStart.TrySetResult(null);
base.OnStart(args);
}
// Called by base.Stop. This may be called multiple times by service Stop, ApplicationStopping, and StopAsync.
// That's OK because StopApplication uses a CancellationTokenSource and prevents any recursion.
protected override void OnStop()
{
ApplicationLifetime.StopApplication();
base.OnStop();
}
}
But it appears that this service based functionality is now built in when UseWindowsService is called on the builder.
So in that case you would need to refactor your code accordingly to get the desired behavior
public class Program {
public static async Task Main(string[] args) {
var isService = !(Debugger.IsAttached || args.Contains("--console"));
var builder = CreateHostBuilder(args);
if (isService) {
await builder.RunAsServiceAsync();
} else {
await builder.RunConsoleAsync();
}
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureServices((hostContext, services) =>
{
services.AddHostedService<Worker1>();
services.AddHostedService<Worker2>();
});
}
public static class ServiceBaseLifetimeHostExtensions {
public static Task RunAsServiceAsync(this IHostBuilder hostBuilder, CancellationToken cancellationToken = default) {
return hostBuilder.UseWindowsService().Build().RunAsync(cancellationToken);
}
}

DELETE return ERROR 405(Method Not allowed) I'm using React and ASP.Net Core

I am attempting to delete a row by using the id on the row. when I Execute it on Local server, it worked correctly,but on plesk server have an error.
Requests CREATE and GET worked correctly but for DELETE and UPDATE not work.
function DELETE:
onDeleteConfirmation(e) {
e.preventDefault();
const { id } = this.props.match.params;
axios.delete("api/Trips/DeleteTrip/" + id).then(result => {
this.props.history.push('/Trips')
});
}
funtion UPDATE:
onUpdateConfirmation(e) {
e.preventDefault();
const { id } = this.props.match.params;
let tripObject = {
name: this.state.name,
description: this.state.description,
dateStarted: this.state.dateStarted,
dateComplated: this.state.dateComplated
}
axios.put("api/Trips/UpdateTrip/"+id, tripObject).then(result => {
this.props.history.push('/Trips')
});
}
Controller Service:
[HttpDelete("DeleteTrip/{id}")]
public IActionResult DeleteTrip(int id)
{
_service.DeleteTrip(id);
return Ok();
}
.
I use ASP.Net Core 3 and React in visual stdio.
my proble accure when I try to execute at online server Plesk.
This is Full controller:
using Microsoft.AspNetCore.Cors;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Trips.Data.Models;
using Trips.Data.Services;
namespace Trips.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class TripsController : ControllerBase
{
public ITripService _service { get; set; }
public TripsController(ITripService service)
{
_service = service;
}
[EnableCors("AnotherPolicy")]
[HttpGet("GetTrips")]
public IActionResult GetTrips()
{
try
{
//throw new Exception();
var allTrips = _service.GetAllTrips();
return Ok(allTrips);
}
catch (Exception ex)
{
return BadRequest(ex.Message);
}
}
[EnableCors("AnotherPolicy")]
[HttpGet("SingleTrip/{id}")]
public IActionResult GetTripById(int id)
{
var trip = _service.GetTripById(id);
return Ok(trip);
}
[EnableCors("AnotherPolicy")]
[HttpPost("AddTrip")]
public IActionResult AddTrip([FromBody] Trip trip)
{
if (trip != null)
{
_service.AddTrip(trip);
}
return Ok();
}
[EnableCors("AnotherPolicy")]
[HttpPut("UpdateTrip/{id}")]
public IActionResult UpdateTrip(int id, [FromBody] Trip trip)
{
_service.UpdateTrip(id, trip);
return Ok(trip);
}
[EnableCors("AnotherPolicy")]
[HttpDelete("DeleteTrip/{id}")]
public IActionResult DeleteTrip(int id)
{
_service.DeleteTrip(id);
return Ok();
}
}
}
.
StartUp.cs
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
// In production, the React files will be served from this directory
services.AddSpaStaticFiles(configuration =>
{
configuration.RootPath = "ClientApp/build";
});
//
services.AddTransient<ITripService, TripService>();
services.AddCors(options =>
{
options.AddPolicy("AnotherPolicy",
builder =>
{
builder.WithOrigins(
"http://hirkansolar.ir/",
"http://react.hirkansolar.ir/"
)
.AllowAnyHeader()
.WithMethods("PUT", "DELETE", "GET", "POST");
});
});
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseStaticFiles();
app.UseSpaStaticFiles();
app.UseRouting();
// ----
app.UseCors();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller}/{action=Index}/{id?}");
});
app.UseSpa(spa =>
{
spa.Options.SourcePath = "ClientApp";
if (env.IsDevelopment())
{
spa.UseReactDevelopmentServer(npmScript: "start");
}
});
}
}
According to Plesk, This is because WebDAV and .NET Core IIS handlers conflict and advised to Disable WebDAV module and its headers from the website configuration.
https://support.plesk.com/hc/en-us/articles/360008566053-HTTP-Error-405-Method-Not-Allowed-when-using-PUT-method-in-ASP-NET-or-NET-Core-application-with-Web-API
Add the following code to your web.config file.
<system.webServer>
<modules>
<!-- Remove WebDAV module so that we can make DELETE requests -->
<remove name="WebDAVModule" />
</modules>
<handlers>
<!-- Remove WebDAV module so that we can make DELETE requests -->
<remove name="WebDAV" />
<add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModuleV2" resourceType="Unspecified" />
</handlers>
other configs here...
</system.webServer>
You might have to this each time before you upload the application files to Plesk panel.
Cheers!
You need to add CORS headers in responses to enable DELETE requests across origins.
https://learn.microsoft.com/en-us/aspnet/core/security/cors?view=aspnetcore-5.0
In your Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options => { // <--- define a policy
options.AddDefaultPolicy(builder => {
builder.WithOrigins(
"http://example.com",
"http://www.contoso.com"
)
.AllowAnyHeader()
.AllowAnyMethod();
});
});
// ...
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
// ...
app.UseRouting();
app.UseCors(); // <--- enable the middleware
// ...
app.UseEndpoints(endpoints => { endpoints.MapControllers(); });
}
After you make this change, responses should include Access-Control-Allow-... headers.

Resources