How to override exception message in ASP.NET Web API - c#

I'm having quite a bit of difficulty in getting a custom exception message to return from my Web Api solution. It's a bit more complicated than that:
I want to override the read only property of the exception with my own:
public class CustomException : Exception
{
public CustomException(string message)
: base(message)
{
}
public CustomException(string message, Exception inner)
: base(message, inner)
{
}
}
However, I also have a global exception handler:
public class GlobalExceptionLogger : ExceptionLogger
{
public override void Log(ExceptionLoggerContext context)
{
if (context.Exception.Message == "Password has already been used in the past...1")
{
throw new CustomException("some msg", context.Exception);
}
NLogger.LogError("Global Error Handler", context.Exception);
}
}
When I throw the error I do so like:
if (some condition)) throw new CustomException("some msg");
And then I catch it in the method like:
catch (CustomException ex)
{
throw ex;
}
catch (Exception ex)
{
NLogger.LogError(ex);
throw;
}
How can I set the message to be "some msg"? What I'm trying to do is have the api return 1-2 use case related error messages with customErrors mode set to on.

throw new HttpResponseException(
new HttpResponseMessage
{
StatusCode = code,
ReasonPhrase = phrase,
Content = new StringContent(body)
});

Related

Propagate exception message from service to controller .NET

I have a .NET appplication where there is a controller for receiving user requests, a service Service 1 which calls another service Service 2.
I have some code in the Service 2 where I query the database(DynamoDB) and get a 500 error in response when the user request values are incorrect. I want to handle this such that I catch this error/exception and send back the error message along with a 400 status code from the controller to the user. How should I modify the code to do this?
This is what I have tried. Currently, I'm just printing the error in Service 1 but I need to send it to the controller. Is sending the error message to the controller by throwing exceptions along the way the right way to do it?
The below code is similar to the actual code
Controller:
[HttpGet]
[Authorize(Policy = "Read-Entity")]
[Route("byParams/{param1}/{param2}")]
[Produces(typeof(DynamoResult<EntityResponse>))]
public async Task<IActionResult> ListByParams([FromQuery] DynamoQuery entityQuery)
{
try
{
return await HandleRequest(async () =>
{
return Ok((await _entityStore.ListByParams(entityQuery)));
});
}
catch (Exception e)
{
return BadRequest(e.Message);
}
}
Service 1:
public async Task<DynamoResult<EntityResponse>> ListByParams(DynamoQuery entityQuery)
{
results = new DynamoResult<Entity>();
try {
results = await GetPagedQueryResults(entityQuery);
}
catch (Exception e) {
Console.WriteLine(e);
}
return new DynamoResult<EntityResponse>
{
Data = results.Data.Select(_mapper.Map<EntityResponse>).ToList(),
};
}
Service 2:
private async Task<DynamoResult<TResponse>> GetPagedQueryResults(DynamoQuery query)
{
var results = new List<Document>();
try{
results = await search.GetNextSetAsync();
}
catch(Exception e){
throw new PaginationTokenException(e.Message);
}
return results;
}
[Serializable]
public class PaginationTokenException : Exception
{
public PaginationTokenException() { }
public PaginationTokenException(string message)
: base(message) {
throw new Exception(message);
}
public PaginationTokenException(string message, Exception inner)
: base(message, inner) { }
}
Assuming you want to hide implementation details from the controller (i.e. you don't want the controller to know/care that it's DynamoDB), I would create a custom exception and throw that from Service1.
Service1 would look something like this:
public async Task<DynamoResult<EntityResponse>> ListByParams(DynamoQuery entityQuery)
{
results = new DynamoResult<Entity>();
try {
results = await GetPagedQueryResults(entityQuery);
}
catch (Exception e) {
throw new MyCustomException('My error message', e);
}
return new DynamoResult<EntityResponse>
{
Data = results.Data.Select(_mapper.Map<EntityResponse>).ToList(),
};
}
In the controller you can then capture that exception explicitly:
[HttpGet]
[Authorize(Policy = "Read-Entity")]
[Route("byParams/{param1}/{param2}")]
[Produces(typeof(DynamoResult<EntityResponse>))]
public async Task<IActionResult> ListByParams([FromQuery] DynamoQuery entityQuery)
{
try
{
return await HandleRequest(async () =>
{
return Ok((await _entityStore.ListByParams(entityQuery)));
});
}
catch (MyCustomException e)
{
return BadRequest(e.Message);
}
}

Exception as FaultContract in WCF?

I'm trying to create a robust way to pass exceptions from the server to the client but I seem to be missing something.
The intention is to use FaultException to wrap actual serializable Exception subclasses caught on the server side, pass them over WCF, then rethrow them at the client side.
Server side code:
[ServiceKnownType(typeof(MyException))]
[ServiceContract]
interface IContract
{
[FaultContract(typeof(MyException))]
[OperationContract]
void Foo();
}
class Service : IContract
{
public void Foo()
{
try
{
Bar();
}
catch (MyException ex)
{
throw new FaultException<MyException>(ex, ex.Message);
}
catch (Exception ex)
{
throw new FaultException(ex.ToString());
}
}
}
Client side code:
try
{
client.Foo();
}
catch (FaultException<MyException> ex)
{
throw ex.Detail;
}
catch (FaultException ex)
{
throw;
}
MyException:
[Serializable]
public sealed class MyException: Exception
{
public MyException(string description)
: base(description)
{
}
public MyException()
{
}
public MyException(string message, Exception innerException)
: base(message, innerException)
{
}
private MyException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
}
}
What I'm observing is that the server side code executes the catch (MyException ex) block but when the fault gets back to the client side, the code goes into the catch (FaultException ex) block and rethrows a normal FaultException, rather than MyException (interestingly, the FaultException does contain the message of the original MyException object).
Note that both the client and server have visibility of MyException, svcutil generates the correct attributes for the client side service contract and the WCF logs don't show any serialization errors.

Throw exception with inner exception in WCF

I am trying to send an exception over the WCF wire but can't figure out what I have done wrong.
I am following the guidance of Oleg Sych and MSDN but to no avail.
What I get back is The requested service, 'net.tcp://mymachine/myservicepath/MyService.svc' could not be activated. See the server's diagnostic trace logs for more information..
[ServiceContract]
public interface ISystemInfoService
{
[OperationContract]
[FaultContract(typeof(MyException))]
void DoThrowException(string message);
}
//[ServiceContract] // <- the culprit
public class SystemInfoService : ISystemInfoService
{
public void DoThrowException(string message)
{
try
{
throw new MyException( "MyMessage" );
}
catch (MyExceptionexc)
{
throw new FaultException<MyException>(exc);
}
}
}
// The custom Exception resides in an common assembly reachable from both server and client.
[Serializable]
public class MyException: Exception
{
...
}
TIA
Can you try handling the exception with a datacontract class instead of serializable exception?
[DataContract]
public class MyExceptionClass
{
[DataMember]
public Exception Exc { get; set; }
}
[ServiceContract]
public interface ISystemInfoService
{
[OperationContract]
[FaultContract(typeof(MyExceptionClass))]
void DoThrowException(string message);
}
public class SystemInfoService : ISystemInfoService
{
public void DoThrowException(string message)
{
try
{
throw new Exception("MyMessage");
}
catch (Exception exc)
{
var data = new MyExceptionClass { Exc = exc };
throw new FaultException<MyExceptionClass>(data);
}
}
}

User made Exception Class

I have to make my own Exception Class for .NET project. Could somebody please help how can I use it in the code? I just to show to MessageBox to user that the images were not found. But I don't know where to do it. Hoping for a good answer.
class RijException : Exception
{
public RijException()
: base() { }
public RijException(string message)
: base(message) { }
public RijException(string format, params object[] args)
: base(string.Format(format, args)) { }
public RijException(string message, Exception innerException)
: base(message, innerException) { }
public RijException(string format, Exception innerException, params object[] args)
: base(string.Format(format, args), innerException) { }
}
Now I want to use it:
try
{
afbeeldingPictureBox.BackgroundImage =
Image.FromFile(#"..\..\Borden\Stilstaan en parkeren\Parkeren toegelaten.png");
}
catch (FileNotFoundException)
{
throw new RijException("Can't find the images");
}
Edit
try
{
try
{
afbeeldingPictureBox.BackgroundImage = Image.FromFile(#"..\..\Borden\Stilstaan en parkeren\Parkeren toegelaten.png");
}
catch (FileNotFoundException)
{
throw new RijException("ImageNotFound");
//MessageBox.Show("Afbeeldingen konden niet worden geladen");
}
}
catch (RijException)
{
MessageBox.Show("Not able to load the image...");
}
Your example could be improved, but before that let's take a more useful example.
Imagine that you have the following code:
class Program
{
static void Main(string[] args)
{
try
{
var processor = new FileProcessor();
processor.Run();
}
catch (RijException exception)
{
//what will I get here.
}
}
}
Which uses the following classes:
public class FileProcessor
{
private string _myFileName;
public void Run()
{
try
{
var fileLoader = new FileLoader();
Process(fileLoader.Load(_myFileName));
}
catch (FileNotFoundException)
{
throw new RijException("Can't find requested file");
}
}
private void Process(object file)
{
//some logic
}
}
public class FileLoader
{
public object Load(string myFileName)
{
//throws FileNotFoundException
}
}
So the call stack will be like this:
If we modify the code in the main method to print the stack trace, what do you think that we get?
try
{
var processor = new FileProcessor();
processor.Run();
}
catch (RijException exception)
{
Console.WriteLine(exception.StackTrace);
}
The correct answer is:
See? The stack trace shows that the error happened in FileProcessor while it really happened in FileLoader. The reason to that is this code:
catch (FileNotFoundException)
{
throw new RijException("Can't find requested file");
}
When you catch an exception and throw another one you must always include the original exception as the inner exception. Otherwise it will be hard to understand where the exception originally occurred.
catch (FileNotFoundException ex)
{
throw new RijException("Can't find requested file", ex); //includes inner
}
Another problem is the exception message: "Can't find requested file". Ask yourself. If you get that message in a log file, would you be able to figure out what went wrong? At least give some context information.
Finally you have another problem. Best practices for designing exceptions says that they should be able to get serialized. To do that you need to include the serialization constructor and mark the exception as serializable:
[Serializable]
public class RijException : Exception
{
public RijException(string message) : base(message)
{
}
public RijException(string message, Exception inner) : base(message, inner)
{
}
//serialization constructor
protected RijException(
SerializationInfo info,
StreamingContext context) : base(info, context)
{
}
Finally I would therefore write your exercise like this:
try
{
var filename = #"..\..\Borden\Stilstaan en parkeren\Parkeren toegelaten.png";
try
{
afbeeldingPictureBox.BackgroundImage = Image.FromFile(filename);
}
catch (FileNotFoundException exception)
{
throw new RijException("Failed to load " + filename, exception);
}
}
catch (RijException)
{
MessageBox.Show("Not able to load the image...");
//now you would have all information required
//to figure out where and why something went wrong.
}
Summary
Always include inner exceptions
Provide useful context information so that you can figure out what went wrong
Make sure that exceptions can be serialized.
It is generally not a great idea to catch an exception that you cannot do much about. Just catching the FileNotFoundException and then throwing a new RijException that essentially conveys the same information is not usually done.
I just to show to MessageBox to user that the images were not found. But I don't know where to do it.
The most direct way to restructure your code to show the message box is
catch (FileNotFoundException)
{
MessageBox.Show("Can't find the images.");
//Don't do this: throw new RijException("Can't find the images");
}
You really do not want your custom RijException to take on the responsibility of displaying the MessageBox.

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