I'm getting this message in the console when running a server-side Blazor app:
Error: There was an unhandled exception on the current circuit, so
this circuit will be terminated. For more details turn on detailed
exceptions in 'CircuitOptions.DetailedErrors'
I've had a look at the Blazor error handling documentation, but I can't work out how to actually turn on the detailed errors mentioned in that message?
More digging on this revealed that there are both non-Blazor specific .NET Core ways to turn on Detailed Errors, and also a Blazor specific approach:
The general .NET Core way to turn on Detailed Errors:
There are a number of ways to get the detailed errors as discussed in the .NET Core documentation, but I ended up using the Detailed Errors setting:
WebHost.CreateDefaultBuilder(args).UseSetting(WebHostDefaults.DetailedErrorsKey, "true")
And the Development Environment setting:
WebHost.CreateDefaultBuilder(args).UseEnvironment(Environments.Development)
Both of those are used in Program.cs:
If you are using the older (and eventually to be deprecated IWebHostBuilder approach) that looks like this:
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseSetting(WebHostDefaults.DetailedErrorsKey, "true")
//.UseEnvironment(EnvironmentName.Development)
.UseStartup<Startup>();
And if you're using the newer IHostBuilder approach that was introduced with Core 2.1 that looks like this:
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder
.UseStartup<Startup>()
.UseSetting(WebHostDefaults.DetailedErrorsKey, "true")
//.UseEnvironment(EnvironmentName.Development);
});
Once I set that I got more details about my misfiring Blazor code.
A Blazor specific approach:
An alternative approach for turning on detailed errors can also be found in this answer, which includes this code:
services.AddServerSideBlazor().AddCircuitOptions(options => { options.DetailedErrors = true; });
This approach can then be expanded to include a check for whether the code is being run in the development environment
services.AddServerSideBlazor().AddCircuitOptions(o =>
{
//only add details when debugging
o.DetailedErrors = _env.IsDevelopment();
});
as highlighted by #Eonasdan's answer below
A better way to add detailed errors is to check your environment first. In Startup.cs add IWebHostEnvironment env to your constructor.
Then you can do this:
services.AddServerSideBlazor().AddCircuitOptions(o =>
{
if (_env.IsDevelopment()) //only add details when debugging
{
o.DetailedErrors = true;
}
});
NO CODE : EASIER & More SECURE
Best Practice
This is easier than most of the proposed solutions and it does not introduce a possible security issue into the code. It is also considered a coding best practice.
Microsoft recommends adding the following to the appsettings.development.json file as it does not add code to the application that can become a security risk. Do not put this in your appsettings.json unless absolutely necessary (and then only temporarily in a staging or dev environment).
You can also use this approach to provide detailed error logging for SignalR.
src: Handle errors in ASP.NET Core Blazor apps: Detailed circuit errors
{
"DetailedErrors": true, // turns on CircuitOptions.DetailedErrors
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information",
"Microsoft.AspNetCore.SignalR": "Debug" // turns on SignalR debugging
}
}
}
For .NET Core 6 you can use WebApplicationBuilder.
var builder = WebApplication.CreateBuilder(args);
if (builder.Environment.IsDevelopment())
{
builder.Services.AddServerSideBlazor().AddCircuitOptions(x => x.DetailedErrors = true);
}
else
{
builder.Services.AddServerSideBlazor();
}
For me it was slightly different
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseSetting(WebHostDefaults.DetailedErrorsKey, "true");
webBuilder.UseStartup<Startup>();
});
Related
I am trying to adapt Application Insights to my liking. And I have some problems. I have it mounted like this.
In the startup.cs class:
public void ConfigureServices(IServiceCollection services)
{
services.AddApplicationInsightsTelemetry();
services.AddControllers();
}
In the Program.cs:
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureLogging(logging =>
{
logging.AddApplicationInsights("73985d32-dc3b-4a7e-915e-aa7ef37fbef8");
logging.AddFilter<ApplicationInsightsLoggerProvider>("", LogLevel.Information);
})
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
So I avoid using the appsettings.json configuration, because the log level will be variable.
My first question is, how can I make the dynamic log level, by querying the database?
Another question, is how can I add a custom parameter, type customer_name?
Finally, how can I make Application Insights register the values that I want, using:
Only record the values that come out of these functions, for example, if there is an exception, you would not have to register it.
_logger.LogInformation("Test info");
_logger.LogError(ex, ex.Message);
About your first question
I think it's impossible,for more details, you can check bowman's answer.
Overriding Log Level for Azure Functions
About second question
Jitendra Patil's code really great, this should be what you need.
Adding custom properties for each request in Application Insights metrics
I have a .net 5 web application that uses Application Insights. I try to log into AI trace by using ILogger<>. However: When analyzing the "traces" - Content in AI on Azure the logs are not shown.
Part of StartUp:
services.AddLogging(loggingbuilder =>
{
loggingbuilder.AddFilter<ApplicationInsightsLoggerProvider>("", LogLevel.Trace);
loggingbuilder.AddApplicationInsights();
});
services.AddApplicationInsightsTelemetry();
The constructor of the class that should do the logging injects ILogger and AppInsights via dependency injection:
public ImportService(ILogger<ImportService> log, TelemetryClient telemetryClient)
{
_log = log;
_telemetryClient = telemetryClient;
}
Inside the method I have the following two logging attempts:
public async Task<Customer> UpdateCustomerByEmail(string email)
{
_telemetryClient.TrackTrace("From Telemetry");
_log.LogWarning("From Log");
[...]
}
While the first one ("from Telemetry") ends up correctly in AI-traces, the second one ("From Log") never shows up there.
The instrumentationkey is stored in the appsettings (and obviously correct because the telemetryClient-Track is working)
Might this documentation be relevant for you? Adding the following code to program.cs worked for me:
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureLogging((hostingContext, logging) =>
{
logging.AddApplicationInsights("<instrumentationKeyHere>");
logging.AddFilter<Microsoft.Extensions.Logging.ApplicationInsights.ApplicationInsightsLoggerProvider>("", LogLevel.Information);
})
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
The nuget package Microsoft.Extensions.Logging.ApplicationInsights must also be installed.
In your case it might be sufficient to simply provide the Instrumentation Key as a paramter to the AddApplicationInsights function.
As stated in the documentation "This code is required only when you use a standalone logging provider. For regular Application Insights monitoring, the instrumentation key is loaded automatically from the configuration path ApplicationInsights: Instrumentationkey."
This might explain why regular monitoring works, but not for logging.
everyone
I've read this issue and found there is support for PEM format certificate in .net core 3.x. I'm trying to use that but I'm not successful. I can not find any sample code on how to use that. what I have is something like this:
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
webBuilder.UseUrls("http://0.0.0.0:8678/");//It works now and this is without https
webBuilder.UseKestrel(options =>
{
//TODO:
});
});
In TODO: I know we have to have something like this:
options.Listen(IPAddress.Loopback, 8678);
options.Listen(IPAddress.Any, 8678);
options.Listen(IPAddress.Loopback, 443,
listenOptions => { listenOptions.UseHttps("certificate.pfx", "password"); });
so, what we have to put instead of "certificate.pfx", "password" ? I really appreciate any help on that.
The path to my certificate in Ubunto machine is:
/etc/letsencrypt/app/fullchain.pem
PEM support is being added in .NET 5, according to this.
The way to do it is by adding in appsettings.json one of the following configuration:
"Certificates":{
"Default":{
"Path": "/some/asp.pem",
"KeyPath": "/some/asp.key",
"Password": "password"
}
}
"Certificates":{
"Default":{
"Path": "/some/asp.pem",
"KeyPath": "/some/asp.key",
}
}
"Certificates":{
"Default":{
"Path": "/some/asp.crt",
"KeyPath": "/some/asp.key",
}
}
Additionally the support for loading certificate chains from configuration is still being developed in this PR and it might be added in NET5 RC2.
According to mentioned PR you need to specify the ChainPath in the configuration file.
I have Lamar set up in my .NET Core 2 project:
public class Program
{
public static void Main(string[] args)
{
IWebHost webhost = CreateWebHostBuilder(args).Build();
//((Container)webhost.Services).GetInstance<IStart>().Run();
webhost.Run();
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseLamar()
.UseStartup<Startup>();
}
...
public class Startup
{
...
public void ConfigureContainer(ServiceRegistry services)
{
services.Configure<Configuration.Auth>("auth", Configuration);
...
services.Scan(s =>
{
s.TheCallingAssembly();
s.WithDefaultConventions();
});
services.AddCors();
services.AddMvc()
.AddJsonOptions(o =>
{
o.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
o.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
})
.SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.AddDbContext<Context>(options => options.UseSqlServer(Configuration.GetConnectionString("defaultConnection")));
}
}
However, when attempting to use Scaffold API Controller with actions, using Entity Framework I run into the following error:
There was an error running the selected code generator: 'No parameterless constructor defined for this object.'
Looking up this https://learn.microsoft.com/en-us/aspnet/core/migration/1x-to-2x/?view=aspnetcore-2.2#update-main-method-in-programcs suggested that this can show up in ASP.NET Core 2 projects that attempt to still use the .NET 1.x structure.
I found a hacky work-around that I'll post below, which suggests that the scaffolding code generation may have an issue with Lamar. However, is there a better solution? Can you set up Lamar to be able to handle Entity Framework Code generation?
Considering EF was failing in the generate code section, I wondered if perhaps the issue was not the parameterless constructor (I'm pretty sure that whatever unnamed object it was referring to actually has one) but the issue with how the WebHost gets built when using Lamar.
The note in the Lamar documentation on integrating with ASP.NET Core states
Note! The Startup.ConfigureServices(ServiceRegistry) convention does not work as of ASP.Net Core 2.1. Use ConfigureContainer(ServiceRegistry) instead.
I was using that Lamar function in my Startup; however, if I changed it back to ConfigureContainer(IServiceCollection services) (and commented out the Lamar-specific functions, such as Scan), I found that I was able to scaffold the EF controller again.
So, at the moment, my workaround is to comment out Lamar before scaffolding, and then uncomment it back once I'm done. I suspect there may be a better solution though...
I have a console application to test HangFire. Here is the code:
using System;
using Hangfire;
namespace MyScheduler.ConsoleApp
{
internal static class Program
{
internal static void Main(string[] args)
{
MyMethod();
Console.WriteLine("[Finished]");
Console.ReadKey();
}
private static void MyMethod()
{
RecurringJob.AddOrUpdate(() => Console.Write("Easy!"), Cron.Minutely);
}
}
}
But it throws an exception on runtime:
Additional information: JobStorage.Current property value has not been
initialized. You must set it before using Hangfire Client or Server
API.
So I need a job storage to run this. But all examples in SQL storage etc. Is there any way to run this example with some kind of memory storage?
JobStorage.Current = new SqlServerStorage("ConnectionStringName", options);
// to
JobStorage.Current = new MemoryDbStorage(string.Empty, options);
You can use Hangfire.MemoryStorage for this.
Simply add this nuget package.
And then you can use it like -
GlobalConfiguration.Configuration.UseMemoryStorage();
For NET Core (web application):
Just to make it very obvious because it wasn't obvious to me.
Install following nuget packages:
Hangfire.AspNetCore (v1.6.17 atow)
Hangfire.MemoryStorage.Core (v1.4.0 atow)
In Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
// other registered services
...
services.AddHangfire(c => c.UseMemoryStorage());
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
// other pipeline configuration
...
app.UseHangfireServer();
app.UseMvc();
}
Anything less than above and my enqueued method did not fire.
As Yogi said, you can use Hangfire.MemoryStorage or Hangfire.MemoryStorage.Core (for .Net Core).
What is missing in that answer is the complete code (for .Net Core) that needs to be put inside ConfigureServices(..) :
var inMemory = GlobalConfiguration.Configuration.UseMemoryStorage();
services.AddHangfire(x => x.UseStorage(inMemory));
Just for the sake of completeness the author of the Hangfire library has added a new package titled Hangfire.InMemory the version of which is available on Nuget. The repository readme positions it as targeting production use. A quote github repo URL is as follows "..an efficient transactional in-memory storage for Hangfire with data structures close to their optimal representation. The result of this attempt should enable production-ready usage of this storage implementation and handle particular properties of in-memory processing.."
The familiar configuration concept applies here as well:
GlobalConfiguration.Configuration.UseInMemoryStorage();
I personally added it as follows:
services.AddHangfire(configuration => { configuration.UseInMemoryStorage(); });