Catch RAISERROR from SQL Server in .NET - c#

I have a stored procedure in SQL Server that throws an error whenever a condition is hit. In order to catch this error and display it to the user, I use
try
{
//code
}
catch (Exception e)
{
return BadRequest(e.Message);
}
This catches most of the cases but on the other hand, this procedure has some print messages that also get caught by this Exception. Is there a way to catch the exception thrown only from RAISERROR and ignore this print message from SQL Server?

All info and error messages generated during command execution are buffered and available when a SqlException is caught. The Message property includes the text of all info messages (print statements and errors with a severity of less than 11) and the warnings/errors that caused the exception.
To ignore info messages, use the SqlException Errors collection and process only those with severity (SqlError.Class property) of 11 or higher:
catch (SqlException e)
{
var sb = new StringBuilder();
foreach(var error in e.Errors)
{
if(error.Class > 10) sb.AppendLine(error.message);
}
return BadRequest(sb.ToString());
}

Related

elmah.axd custom exception message with stacktrace of child throwed exception in C#

What I want to achieve is to show a custom exception Type and Error message in elmah.axd table but with the original stacktrace of a child throwed exception.
This is just an example of a nested try catch that match my needs:
// custom exception constructor
public MyCustomException(string customMsg, Exception expt):base(customMsg,expt)
// my test case
try{
try{
//_context.saveChanges(); --> this will generate an exception
// but for this example we'll throw the following
throw new IndexOutOfRangeException();
}
catch (Exception e){
// here elmah will print in the Type column "IndexOutOfrange" and in the Error column the message: "Index was outside the bounds of the array. Details..."
ErrorSignal.FromCurrentContext().Raise(e);
// now I throw a custom exception with the original stacktrace of "IndexOutOfrangeException"
throw new MyCustomException("Message to see in elmah 'Error' column", e)
}
}
catch(MyCustomException cex){
// here elmah will also print in the Type column "IndexOutOfrange" and in the Error column the message: "Index was outside the bounds of the array. Details..." with the original stacktrace
ErrorSignal.FromCurrentContext().Raise(cex)
// my expectation would be to print in the Type column "MyCustomException" and in the Error column the message: "Message to see in elmah 'Error' column Details..." with the original stacktrace
}
catch(Exception ex){
// some code here
}
Am I doing something wrong or it's just not possible what I want?
ELMAH always uses the base exception to generate the Type and Error fields. This is the best (IMO) way of doing it since the base exception will always be the original cause of the error. This explains why you get the type and message of the IndexOutOfRangeException logged in ELMAH.
There's a small "hack" to resolve this if you switch to using the Log method:
try{
try{
throw new IndexOutOfRangeException();
}
catch (Exception e){
throw new MyCustomException("Message to see in elmah 'Error' column", e)
}
}
catch(MyCustomException cex){
var error = new Elmah.Error(cex);
// Type and Error will now have the values of `IndexOutOfRangeException`
error.Type = cex.GetType().FullName;
error.Message = cex.Message;
// I manually updated the values from `MyCustomException`
ErrorLog.GetDefault(HttpContext.Current).Log(error);
}
catch(Exception ex){
// some code here
}
I tested this locally and both Type and Error get the value from the outer exception.

C# Retry Policy: How to check what exception you receive as a variable?

I have a retry policy created for SQL Exceptions but it seems to not be retrying properly.
I am currently trying to debug and I want to create a temporary code line to test if the exception is a SQL Exception:
if (exception == SQLException) then bool correct = true;
But how would I create an exception variable?
I am currently causing the exception by using RAISERROR('test', 16, 1); in the stored procedures in the database and also creating a SQL timeout.
Just want to check if the exception I'm receiving is a SQL Exception or if it's not even registering.
Thank you
Not sure enough about the context, but if you have the exception object, then try the is operator
if (ExceptionObject is SqlException )
{
//run the retry logic for SqlException
}
The details are here:
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/type-testing-and-cast
Just catch the SqlException and check for the Class and State properties:
if (exception is SqlException sqlException)
{
if(sqlException.Class == 16 && sqlException.State == 1)
{
}
}

How to get user defined SQLException number with Dapper

My stored procedure is throwing custom errors to handle validation within a multi user web app. This is working as expected in SQL Server with error number 50001 being returned however when my C# code catches the error it always has the error number 50000 instead of 50001 therefore I cannot treat the errors differently.
How can I catch error number 50001? Note that I am using Dapper to execute all stored procedures.
SQL
THROW 50001, 'Client already has an Active Visit! THIS IS DEV!!!!',1;
Msg 50001, Level 16, State 1, Line 1
Client already has an Active Visit! THIS IS DEV!!!!
C#
catch (SqlException ex)
{
var errorHandler = new ErrorHandler();
var msg = errorHandler.ErrorMessage(ex);
if (ex.Number == 50001)
{
return BadRequest(msg);
}
else
{
return StatusCode(500, msg);
}
}
catch (Exception ex)
{
var errorHandler = new ErrorHandler();
return StatusCode(500, errorHandler.ErrorMessage(ex));
}
EXAMPLE
SQL server error 50000 is reserved for general user defined message, so it sounds like it's not finding error 50001 in sys.messages. You can try to add the error using the stored procedure sp_addmessage.
Once that is done, you can call it like this:
RAISERROR(50001, 1, 1)
Another reason it could be error 50000 is if you are raising the SQL error in a SQL TRY/CATCH as that will always return a 50000 error code.
Just tried this code myself:
using (var cmd = new SqlCommand("THROW 50001,'error',1;", conn))
{
cmd.ExecuteNonQuery();
}
And that does return ex.Number 50001 so it must be a problem in your SQL. Like I said above, it could be caused by a TRY/CATCH as this won't save the original error code number.

Get Exception type from an exception

I have a application to connect SAP with an RFC call and I need to show a notification to the user when connection failed while try to establish the RFC call with SAP. And I'm getting the following exception.
{
SAP.Middleware.Connector.RfcCommunicationException:
LOCATION CPIC (TCP/IP) on local host with Unicode
ERROR partner '151.9.39.8:8010' not reached
TIME Wed Jul 16 10:32:05 2014
RELEASE 720
COMPONENT NI (network interface)
VERSION 40
RC -10
MODULE nixxi.cpp
LINE 3286
DETAIL NiPConnect2: 151.9.39.8:8010
SYSTEM CALL connect
ERRNO 10060
ERRNO TEXT WSAETIMEDOUT: Connection timed out
COUNTER 2
}
And by using this exception I need to notify the user. But how can I identify whether it is a SAP.Middleware.Connector.RfcCommunicationException or not because I'm handling other exceptions too. Is there any way to get the type of the exception without concatenating the above exception string.
In my try catch block
I'm currently doing this but it is not working.
catch (Exception ex)
{
if (ex.ToString().ToLower() == "rfccommunicationexception")
{
MessageError = "RFC error";
}
}
Catch the exception explicitly:
catch(SAP.Middleware.Connector.RfcCommunicationException)
{
// RFC exception
}
catch(Exception e)
{
// All other exceptions
}
The best approach to this is to have multiple catch blocks:
try
{
// your code
}
catch(RfcCommunicationException rfcEx)
{
// handle rfc communication exception
}
cathc(Exception ex)
{
// handle other exception
}
You can use is
For example:-
catch (Exception exception )
{
if (exception is SAP.Middleware.Connector.RfcCommunicationException)
{
////Your code
}
}
Or as Resharper suggest its better to catch specific exception as shown below :-
catch(SAP.Middleware.Connector.RfcCommunicationException)
{
// Your code
}
You could try this one:
// Catch the exception
catch(exception e)
{
// Check if the type of the exception is an RFC exception.
if(e is SAP.Middleware.Connector.RfcCommunicationException)
{
}
else // It is not an RFC exception.
{
}
}
Or you could try to catch each exception separately like below:
catch(SAP.Middleware.Connector.RfcCommunicationException exception)
{
}
catch(exception e)
{
}

C# oracle : catch all exceptions relative to connectivity?

In c#, can I catch all errors about (non) connectivity to an Oracle database?
I don't want to catch error about badly written query but only errors like No listener, connection lost...
If queries are badly written (or table are missing) then this is my fault.
But if Oracle or the network is down then this should be held by another department.
Write your code in which you build the connection in a try catch part:
try
{
BuildConnection(connectionString);
}
catch (OracleException ex)
{
//Connectivity Error
}
Errors between ORA-12150 to ORA-12236 are related to connection errors. A few examples:
ORA-12154: TNS:could not resolve the connect identifier specified
ORA-12152: TNS:unable to send break message
ORA-12157: TNS:internal network communication error
Please refer to https://docs.oracle.com/cd/E11882_01/server.112/e17766/net12150.htm
Simple answer for this Type of problem is Use Try Catch Block like
try
{
// your code
}
catch (OracleException ex)
{
}
MSDN HELP
Sure - you can catch specific exception types, or if they're all the same exception type, you can catch it, check to see if it's a specific type, and re-throw ones you don't want to handle. Not having your syntax, here's an example...
try
{
// your Oracle code
}
catch (OracleException ex)
{
if (ex.Message == "Something you don't want caught")
{
throw;
}
else
{
// handle
}
}
errors like No listener, connection lost are still caught in System.Data.SqlClient.SqlException, however, you may inspect ErrorCode and Errors to handle different situations accordingly, say, not listener or connection lost etc.
MSDN does not seem to document all possible errors, however, you may write a few unit tests or integration tests to learn what appear in ErrorCode and Errors, then write error handlers in production codes accordingly.
OracleException contains only ErrorCode not Errors. So you may be using switch(e.ErrorCode) to handle different situations.
I observed that each time a network exception occurs, then a SocketException can be found in inner exceptions.
I also observed that when a network exception occurs, the first inner exception is of type «OracleInternal.Network.NetworkException» but unfortunately, this class is internal...
Based on this observations, I would code something like this:
public void RunQuery()
{
try
{
var con = new OracleConnection("some connection string");
con.Open();
var cmd = con.CreateCommand();
// ...
cmd.ExecuteNonQuery();
}
catch (Exception ex) when (IsNetworkException(ex))
{
// Here, a network exception occurred
}
catch (Exception ex)
{
// Here, an other exception occurred
}
}
private static bool IsNetworkException(Exception ex)
{
var exTmp = ex;
while (exTmp != null)
{
if (exTmp is SocketException)
return true;
exTmp = exTmp.InnerException;
}
return false;
}

Categories

Resources