Modify exception data while logging with NLog - c#

I have a global try/catch around my application methods to log unhandled exceptions and show an error message. For logging I use NLog. If I handle an exception and log it manually I set a key 'logged' in the exceptions data object to prevent the second log from the global try/catch.
public partial class App : Application
{
public static void Main(string[] args)
{
try
{
// Application stuff
SomeMethod();
}
catch (Exception ex)
{
if (ex.Data['logged'] == false)
{
logger.Error(ex, "A unhandled exception occured.")
ex.Data['logged'] = true;
}
// Show error dialog
}
}
public static void SomeMethod()
{
try
{
// Method stuff
}
catch (Exception ex)
{
logger.Error(ex, "A handled exception occured.")
ex.Data['logged'] = true;
throw;
}
}
}
I want to simplify the process so that I don't have to call ex.Data['logged'] = true; manually. Is there a way to modify the data property of an exception automatically while logging with NLog? I tried to use a MethodCall-Target but I had no access to the exception reference. The exception could only be passed as a string.

Would it work for you to use NLog to perhaps modify your approach to logging exceptions slightly?
public partial class App
{
private static Logger logger = NLog.LogManager.GetCurrentClassLogger();
public static void Main(string[] args)
{
try
{
SomeMethod();
}
catch (Exception ex)
{
logger.ErrorEx(ex, "message");
}
}
public static void SomeMethod()
{
try
{
// Method stuff
}
catch (Exception ex)
{
logger.ErrorEx(ex, "A handled exception occured.");
throw;
}
}
}
public static class NLogExt
{
public static void ErrorEx(this NLog.Logger logger, Exception ex, string message)
{
if (ex.Data["logged"] as bool? == true) return;
logger.Error(ex, message);
ex.Data.Add("logged", true);
}
}

Related

Strange behavior of exception propagation

This is an example from https://learn.microsoft.com/en-us/dotnet/standard/parallel-programming/exception-handling-task-parallel-library
I have tried to execute it in Visual Studio 2022, C#10, Net 6 but exception is not propagated to try catch block.
We can emulate some delay to force it to propagate (via sleep, or task.Wait(10), ...) but this is not documented.
Is this some kind of compiler optimization or is it bug?
public class Program
{
public static void Main()
{
var task = Task.Run(
() => {
//Thread.Sleep(10); //if uncomment then exception is propagated
throw new CustomException("This exception is expected!");
});
try
{
task.Wait(); //we can use task.Wait(1) then exception is caught
}
catch (AggregateException ae)
{
foreach (var ex in ae.InnerExceptions)
{
// Handle the custom exception.
if (ex is CustomException)
{
Console.WriteLine(ex.Message);
}
// Rethrow any other exception.
else
{
throw ex;
}
}
}
}
class CustomException : Exception
{
public CustomException(string s) : base(s) { }
}
}

Logging exception without catching it

I want to log an unhandled exception in my domain layer without catching it.
I mean that the exception should be thrown after logging to be caught again in upper levels. As you know, throwing has an overhead that I want to avoid.
Any idea in Dotnet platform (C#) ?
public static void Main(string[] args)
{
try
{
throw new System.Exception("some exception");
}
catch (System.Exception ex) when (LogUsingSerilogOrNLogOrBla(ex)) { }
finally
{
Console.WriteLine("exception logged, but not handled :), there is no need to throw");
}
}
public static bool LogUsingSerilogOrNLogOrBla(System.Exception ex)
{
Console.WriteLine(ex);
return false;
}

How to get the values from inside the code when exception occurs?

I have a worker service in .net core 3.1
in my Program.cs i have the below codes
public static void Main(string[] args)
{
try
{
CreateHostBuilder(args).Build().Run();
}
catch(Exception ex)
{
Handler(ex);
}
}
static void Handler( Exception e)
{
var logger = NLogBuilder.ConfigureNLog("nlog.config").GetCurrentClassLogger();
List<Test> _Test = new List<Test>()
{
new Test()
{
}
};
LogEventInfo eventInfo = new LogEventInfo
{
Level = LogLevel.Error,
Properties = { { "Application",_Test } }
};
logger.Log(eventInfo);
}
private class Test
{
public string Name{get;set;}
public string Place{get;set;}
}
In my worker class i have code as below
public class Worker : BackgroundService
{
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
do
{
string Name ="MyName";// These values will be fetched from different file
string Place="MyPlace";
//Some Logic where an exception may occur
}
while (!stoppingToken.IsCancellationRequested);
}
}
Is there anyway to get the values of Name and Place of worker class to Handler method in program class when an exception arises. Since I'm thinking of a global exception handler I'm thinking of not putting any more try catch blocks. I want to handle all the exception with the try catch in the program.cs file. How can i get the Name and Place values onto my handler on such scenario so that it can be logged?
While a custom exception is a possibility, you could also simply decorate any exception thrown inside your service with those properties using the Data property:
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
do
{
string Name = "MyName";
string Place = "MyPlace";
try
{
//Some Logic where an exception may occur
}
catch (Exception e)
{
e.Data["Name"] = Name;
e.Data["Place"] = Place;
throw;
}
}
while (!stoppingToken.IsCancellationRequested);
}
Create a custom Exception class where you can set Name & Place as properties.
In the Worker, add a try catch block around the code that may throw an exception. Create and throw your custom exception, setting the original exception as the InnerException (https://learn.microsoft.com/en-us/dotnet/api/system.exception.innerexception?view=net-6.0)
Then in your handler get the name / place from the wrapper exception, and then use the InnerException for the rest.

Handling exception in task

I'm new to TPL.
I need to handle exception when the SendEmailAlert() method throws any error.Is the following code correct please?
public Task MyMethod()
{
DoSomething();
try
{
string emailBody = "TestBody";
string emailSubject = "TestSubject";
Task.Run(()=> SendEmailAlert(arrEmailInfo));
}
catch (AggregateException ex)
{
ex.Handle((e) =>
{
log.Error("Error occured while sending email...", e);
return true;
}
);
}
}
private void SendEmailAlert(string[] arrEmailInfo)
{
MyClassX.SendAlert(arrEmailnfo[0], arrEmailnfo[1]);
}
I forced an error from within SendEmailAlert() method.But the exception is not getting caught. Could someone advise?
Thanks.
Your Task.Run runs in a different context (you would need a try/catch inside it; or check if the task is done). You could change to use async/await.
Example:
public async void MyMethod()
{
try
{
await ExceptionMethod();
}
catch (Exception ex)
{
// got it
}
}
public async Task ExceptionMethod()
{
throw new Exception();
}

Custom error handling ASP.NET

I want to use custom exception handling, for example
instead of using (Exception ex) i want to use (LoginException ex) or (RegistrationException ex) or (SomeNameException ex)
is it possible to design such custom exception handling in ASP.NET webforms?
Yes but what you need to do is first create your own custom exceptions. You need to derive your exception from the Exception base class. Heres an example:
[Serializable]
public class LoginFailedException: Exception
{
public LoginFailedException() : base()
{
}
public LoginFailedException(string message)
: base(message)
{
}
public LoginFailedException(string message, Exception innerException)
: base(message, innerException)
{
}
protected LoginFailedException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
}
}
Then in your code, you would need to raise this exception appropriately:
private void Login(string username, string password)
{
if (username != DBUsername && password != DBPassword)
{
throw new LoginFailedException("Login details are incorrect");
}
// else login...
}
private void ButtonClick(object sender, EventArgs e)
{
try
{
Login(txtUsername.Text, txtPassword.Text);
}
catch (LoginFailedException ex)
{
// handle exception.
}
}
You mean something like:
try{
somefunc();
}catch(LoginException ex){
}catch(RegistrationException ex){
}catch(SomeNameException ex){
}
Or do you mean coding the classes to throw the exceptions?

Categories