1

I've this error, which occurs on a webapi I build:

An unhandled exception occurred and the process was terminated.

Application ID: /LM/W3SVC/1/ROOT/MyWebAPI

Process ID: 43144

Exception: IBM.Data.DB2.iSeries.iDB2SQLErrorException

Message: SQ20377 Character X'  3F' cannot be mapped to a valid XML character.

StackTrace:    at IBM.Data.DB2.iSeries.iDB2Exception.throwDcException(MpDcErrorInfo mpEI, MPConnection conn)
   at IBM.Data.DB2.iSeries.iDB2Command.reportDCError(Int32 rc)
   at IBM.Data.DB2.iSeries.iDB2Command.fetch()
   at IBM.Data.DB2.iSeries.iDB2DataReader.MPDataReader.FetchData(UInt32& rowsReturned, UInt32& blockNumber)
   at IBM.Data.DB2.iSeries.iDB2DataReader.MPDataReader.FetchThread()
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Threading.ThreadHelper.ThreadStart()

Every query to DB2 are catched, so any error should be logged and managed. But instead, "sometimes" (not always) the whole application pool go down due to these errors.

I said sometimes because some of those errors on Event Viewers (which are the same) are logged, but don't stop the IIS pool.

Its running .NET v4.0.

What can it be? Can a try/catch be bypassed? Very weird...

EDIT:

most try/catch are generic:

try
{

}
catch (Exception ex)
{

}

some are specifics, such as:

int rowCount = 0;
SqlBuilder.Template template = null;

try
{
    template = CreateSQLTemplate(filters, "rowcount");

    using (iDB2Connection db2 = new iDB2Connection(Properties.Settings.Default.AS400Connection))
    {
        var rowCounts = db2.Query<int>(template.RawSql, template.Parameters);
        rowCount = rowCounts.Count() > 0 ? rowCounts.First() : 0;
    }
}
catch(iDB2SQLErrorException db2Sqlex)
{
    //
}
catch (Exception ex)
{
    //
}

This can be enough, can't be?

markzzz
  • 47,390
  • 120
  • 299
  • 507
  • 1
    An unhandled exception is an exception that hasn't been caught i.e. wrapped in a `try..catch` block.. – Johnathan Barclay Feb 24 '21 at 13:37
  • 1
    Can we see your `catch` ? There are some exceptions that can't be reliably caught (out-of-memory, stack-overflow and thread-abort in particular), but most : will be caught just fine. If you're seeing the exception unexpectedly: you possibly aren't catching what you think you are catching – Marc Gravell Feb 24 '21 at 13:38
  • of course there´s little point in trying to catch an outofmemoryexception, as everything you may do within such a handler would itself consume memory - which obviously you don´t have. That´s why some exceptions *do* bypass a catch. – MakePeaceGreatAgain Feb 24 '21 at 13:40
  • 2
    As for it taking down the entire process: yes, that happens if an exception hits the top of the stack. It looks like you're running your own thread here, so... yeah, don't let that (unhandled exception) happen – Marc Gravell Feb 24 '21 at 13:40
  • @MarcGravell added my catches. They seems ok, no? – markzzz Feb 24 '21 at 13:44
  • Are we to assume you're not writing code in the `IBM.Data.DB2.iSeries` namespace? If so, that call stack seems to show entirely MS/IBM code - so any `try`/`catch` in *your* code isn't in the stack. – Damien_The_Unbeliever Feb 24 '21 at 13:45
  • 2
    @markzzz well, the code you've added won't compile - there is at least one missing brace; and it isn't clear where they fit in terms of your other code, so... it is impossible to comment – Marc Gravell Feb 24 '21 at 13:46
  • @MarcGravell updated with a more complete example. Would that help now? – markzzz Feb 24 '21 at 14:01
  • It looks to me like the exception is thrown by a DB2 worker thread. I would have expected such exceptions to be forwarded to the actual calling thread instead of being left unhandled, but that does not seem to be the case. – JonasH Feb 24 '21 at 14:03
  • 1
    @JonasH that would be a fundamentally broken data provider, though; not saying that isn't what is happening, but rather: if it is, wow that's stupid by whoever wrote that IBM layer – Marc Gravell Feb 24 '21 at 14:17
  • The call stack indicates an async call which does not match the code snippet you shared, so it won't be caught by this try...catch. – Lex Li Feb 24 '21 at 14:18
  • 1
    Small example of a scenario that can bypass `try` `catch`: https://dotnetfiddle.net/rQE5Bi –  Feb 24 '21 at 14:21
  • @LexLi async call... where? How can I intercept it? – markzzz Feb 24 '21 at 14:37
  • you are missing a code block that is not controlled with a catch exception, you need to re-check al the implementations or check the iis server logger to see where the .net app is going down – crizcl Feb 24 '21 at 14:40
  • @Knoop is there any way to intercept an async thread exception? – markzzz Feb 24 '21 at 14:42
  • 2
    @markzzz this specific case is due to the combination of how `async void` works and how exceptions are handled in `async` context (they're normally attached to the `Task` object which is absent for `async void` signatures, resulting in the exception being raised in the original thread no matter where that thread is at that time). So in this example it's fixed if you change the signature to `async Task` (and you should then correctly `await` that `Task`. But was mostly to just give an example that an exception can "bypass" a try catch block. –  Feb 24 '21 at 15:25
  • So no way to resolve it? Damn, this problem can be heavy on every app using DB2 :O – markzzz Feb 24 '21 at 15:31
  • @markzzz Are there any error messages in the Event Viewers? – samwu Feb 25 '21 at 02:32
  • @samwu the message I've posted is from Event Viewers... – markzzz Feb 25 '21 at 06:39
  • @all also, as said in the topic, why it crash the app "sometimes"? I see like 10 message in a day about the same errors, but only sometimes the pool go down. Should be the same behaviour every time? – markzzz Feb 25 '21 at 08:16
  • As mentioned earlier this could be due to an unobserved exception in the `async` call. In .NET 4 a task with an unobserved exception will terminate the process when the task is garbage collected. Therefore this could happen only sometimes depending on when garbage collection happens. – Jeroen Mar 12 '21 at 21:36
  • @Jeroen how would you fix it so? – markzzz Mar 12 '21 at 21:39
  • Neve tried this myself but there is a node called `ThrowUnobservedTaskExceptions` in configuration -> runtime. If you set the enabled property to false this should not happen. More info can be found in example section here https://learn.microsoft.com/en-us/dotnet/framework/configure-apps/file-schema/runtime/throwunobservedtaskexceptions-element – Jeroen Mar 12 '21 at 21:44
  • Please post your `Main` method, it should have a try/catch around the entire body and any async calls should have await in the try block. – jjxtra Mar 15 '21 at 21:54
  • @markzzz this has been neglected IMO: The exception indicates an error in XML parsing during data-fetching. You should narrow down your search to code areas where you read XML data from the db, or where the DB2 provider needs to read XML internally for some reason (I don't know DB2 very well). Maybe there's some framework code causing this exception, such as an auth/identity framework trying to read an XML in a user record. Pure speculation, but that's all we've got... – Marco Mar 17 '21 at 08:13

5 Answers5

1

You try set EnablePreFetch=false in connection string?

https://www.ibm.com/mysupport/s/question/0D50z000060GNJx/threading-issue?language=en_US

https://social.msdn.microsoft.com/Forums/vstudio/en-US/8f487219-22ad-48cc-b743-aa15c8d7dd4f/threading-exception?forum=clr

Genusatplay
  • 761
  • 1
  • 4
  • 15
  • That would also be my first bet. – Alois Kraus Mar 17 '21 at 15:08
  • What this would do? Which is the terms of impact? – markzzz Mar 17 '21 at 16:34
  • in second link Solution from IBM: `Your call stack shows that the exception is happening inside a thread that the provider kicks off, which handles pre-fetching data (a performance thing). Try turning off the prefetch in the ConnectionString (EnablePreFetch=false), and then put your exception handling around the long-running query.` – Genusatplay Mar 17 '21 at 17:39
0

The .NET Framework provides a couple events that can be used to catch unhandled exceptions. You only need to register for these events once in your code when your application starts up. For ASP.NET, you would do this in the Startup class or Global.asax

static void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
{
     // Log the exception, display it, etc
     Debug.WriteLine(e.Exception.Message);
}

static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
     // Log the exception, display it, etc
     Debug.WriteLine((e.ExceptionObject as Exception).Message);
}
samwu
  • 3,857
  • 3
  • 11
  • 25
  • Tried your solution. But I still see unhandled exception on Event Viewer, and don't I see any (custom) log :( damn this seems terrible... – markzzz Mar 02 '21 at 11:28
0

Do you have tried to subscribe to this event? TaskScheduler.UnobservedTaskException Event

This behavior is changed since .NET framework 4.5 but you can enable it to have maybe more details for the origin of this exception.

The event is a static one, it's recommended to subscribe to this event as soon as possible at the start of your application.

Don't miss editing the configuration file

<runtime>
    <ThrowUnobservedTaskExceptions enabled="true"/>
</runtime>

This an example of use tpl-exception-handling

Notice this also Release mode

Hope this helps

G. Sofien
  • 234
  • 3
  • 11
  • Where do I subscribe It? Example? – markzzz Mar 17 '21 at 05:56
  • 3
    This is not a TPL Task. The call stack clearly shows no unhandled TPL Task. This was a manually started thread by the IBM SQL Provider for prefetching data as far as I can read. – Alois Kraus Mar 17 '21 at 15:09
0

Try turning on connection pooling in your DB connection:

var connb = new DB2ConnectionStringBuilder(ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString);
connb.Pooling = true;
connb.MinPoolSize = 1;
connb.MaxPoolSize = 100;
var conn = new DB2Connection(connb.ConnectionString);

If you can't or don't want to do that, make sure to explicitly close every single connection to the db after you're done with it. Otherwise an unhandled exception may be thrown when the garbage collector picks up your open connection objects. This problem has been observed before with the DB2 provider.

Marco
  • 700
  • 5
  • 11
  • I close all the connection (if you see the code, there is "using"). – markzzz Mar 17 '21 at 05:56
  • What about connection pooling on? Which tag should i use? – markzzz Mar 17 '21 at 05:56
  • @markzzz yes I saw the using, but I wanted to emphasize that you need to make sure it's used everywhere. Can you try closing the connection explicitly using Close() at the end? I know it's almost esotheric, but I'm not sure how IBM implemented the connection under the hood. About the pooling, I updated my post. – Marco Mar 17 '21 at 08:04
0

According to the stack trace, this exception happens in a thread that DB2 creates automatically. It doesn't run any of your code so you can't catch this exception with a try block.

  1. Configure the Visual Studio debugger to break on unhandled exceptions.
  2. Try to find out where that strange-looking character comes from. Those two blanks in front of the 3F look suspicious.
Ron Inbar
  • 2,044
  • 1
  • 16
  • 26
  • Point 1: what should I do? Can you show to me the steps? For point 2: there are involved so many tables/data, we are not able to individuate it. – markzzz Mar 17 '21 at 16:33
  • [This article](https://learn.microsoft.com/en-us/visualstudio/debugger/managing-exceptions-with-the-debugger?view=vs-2019) explains what to do, but you need to be able to reproduce the problem with the debugger attached. Failing that, I would try to use just-in-time debugging as explained [here](https://learn.microsoft.com/en-us/visualstudio/debugger/debug-using-the-just-in-time-debugger?view=vs-2019). – Ron Inbar Mar 17 '21 at 19:26