5

I have an application that stores some data in firebird database. I'm using an embedded firebird server and EntityFramework and all works greatfully but when I close my app by x button on form I get a windows system message "application has stopped working" and I can't catch this exception. I have an UnhandledExceptionHandler in my app :

// Add handler for UI thread exceptions
Application.ThreadException += new ThreadExceptionEventHandler(UIThreadException);

// Force all WinForms errors to go through handler
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);

//This handler is for catching non-UI thread exceptions 
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);

.....some other code..........

Application.Run(new MainForm());

But this kind of exception never been catched by it. So I went to windows event log and found there this xml-view of error-event :

- <Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
- <System>
  <Provider Name="Application Error" /> 
  <EventID Qualifiers="0">1000</EventID> 
  <Level>2</Level> 
  <Task>100</Task> 
  <Keywords>0x80000000000000</Keywords> 
  <TimeCreated SystemTime="2017-03-14T23:06:25.000000000Z" /> 
  <EventRecordID>36077</EventRecordID> 
  <Channel>Application</Channel> 
  <Computer>MYPC</Computer> 
  <Security /> 
  </System>
- <EventData>
  <Data>MyApp.exe</Data> 
  <Data>1.0.0.0</Data> 
  <Data>58c7a3f0</Data> 
  <Data>fbintl.DLL</Data> 
  <Data>2.5.5.26952</Data> 
  <Data>5644432f</Data> 
  <Data>c0000005</Data> 
  <Data>00004e9c</Data> 
  <Data>1d64</Data> 
  <Data>01d29d1797fb7f0d</Data> 
  <Data>G:\Programming\WorkSpace\C#\MyApp\bin\x86\Debug\MyApp.exe</Data>
  <Data>G:\Programming\WorkSpace\C#\MyApp\bin\x86\Debug\FireBirdEmbeddedServer\intl\fbintl.DLL</Data> 
 <Data>d84a6ca6-090a-11e7-8151-005056c00008</Data> 
 </EventData>
 </Event>

As you see something went wrong with fbintl.DLL when app has closed already. So how I can get more detailed description about this problem?

UPD I make an app more shorter to detect a reason of my problem - now ONLY this EF code runs before app close

 public async Task GetAutoAnswerTemplate()
    {           
       try
        {
          using (var db = new FirebirdDbContext(embeddedConnectionString)){
            //Async or sync methods doesn't affect to my problem
             AutoAnswerTemplate template = await dbContext.AutoAnswerTemplate.FirstOrDefaultAsync();
            return template?.AutoAnswer_body;
          }
        }
        catch (Exception ex)
        {
            throw new EmbeddedFbDataBaseTools.EmbeddedDbException(
                "Error while getting auto answer template" + "\r\n" +  ex.Message, ex);
        }
    }

Where FirebirdDbContext is :

public class FirebirdDbContext : DbContext
{

    public FirebirdDbContext(string connString)
        : base(new FbConnection(connString), true)
    {
        //* The Entity initializer is bugged with Firebird embedded: http://stackoverflow.com/q/20959450/2504010  so I didn't use default--->
        //  Database.SetInitializer<FirebirdDBContext>(new CreateDatabaseIfNotExists<FirebirdDBContext>());    
        Database.SetInitializer<FirebirdDbContext>(new MyCreateDatabaseIfNotExists());
    }

    public DbSet<AutoAnswerTemplate> AutoAnswerTemplate { get; set; }
    public DbSet<User> User { get; set; }


}

class MyCreateDatabaseIfNotExists : IDatabaseInitializer<FirebirdDbContext>
{
    public void InitializeDatabase(FirebirdDbContext context)
    {
        if (!context.Database.Exists())
        {
            context.Database.Create();
        }
    }
}

And connection params is

  public static string GetEmbeddeddefaultConnectionString()
    {
        FbConnectionStringBuilder builder = new FbConnectionStringBuilder
        {
            ServerType = FbServerType.Embedded,
            DataSource = "localhost",
            Port = 3050,
            Database = EmbeddedDbPath, //Path to embedded db
            ClientLibrary = EmbeddedServerDllPath,
            UserID = "SYSDBA",
            Password = "masterkey",
            Charset = "WIN1251",
            Dialect = 3,
            ConnectionLifeTime = 15,
            Pooling = true,
            MinPoolSize = 0,
            MaxPoolSize = 50
        };
        return builder.ToString();
    }

NEW UPDATE 25.04.2017

I made a simple app with firebird embedded db that demonstrates the error. U can find it here

The app creates a firebird embedded database and connects to it in background thread (Task TPL), and after work is done (_bgTask.Status == TaskStatus.RanToCompletion) u close the app and get the error.

whizzzkey
  • 926
  • 3
  • 21
  • 52
  • Which version of Firebird Embedded are you using? I'm not entirely sure, but I believe some of the older versions did not cleanup correctly under certain conditions, for example http://tracker.firebirdsql.org/browse/CORE-5117 (fixed in 2.5.6) – Mark Rotteveel Mar 15 '17 at 08:18
  • @MarkRotteveel I'm using firebird 1.5.6 and in other app firebird 2.5.6 - Error occurs in both – whizzzkey Apr 21 '17 at 01:54
  • Running async code on application shutdown might not work as you expect. Try to remove everything async from GetAutoAnswerTemplate (make it synchronous) and see if that helps (just to diagnose the problem, not as a final solution). – Evk Apr 21 '17 at 02:54
  • Also try to subscribe to TaskScheduler.UnobservedTaskException and see if it ends there. Which .NET Framework version you have? – Evk Apr 21 '17 at 03:04
  • @Evk I'm using .net 4.0. "Also try to subscribe to TaskScheduler.UnobservedTaskException" - how to subscribe to it? – whizzzkey Apr 21 '17 at 03:43
  • Well that is static event, subscribe as usual. https://msdn.microsoft.com/en-us/library/system.threading.tasks.taskscheduler.unobservedtaskexception(v=vs.110).aspx – Evk Apr 21 '17 at 03:49
  • @Evk I've just added an UnobservedTaskException handler and still can't catch the exception – whizzzkey Apr 21 '17 at 04:57
  • If you remove all code which runs on application close, will error go away? If yes - please post all code you run on close, starting from the root (application exit or form close event). – Evk Apr 21 '17 at 05:45
  • 1
    I suspect that that issue has nothing in common with EF, but the `async` function. That's why it's important to see the usage - where and and how is that function called. In other words, [mcve]. – Ivan Stoev Apr 21 '17 at 14:37
  • If you comment out the ef code, goes the exception away? – Sean Stayns Apr 22 '17 at 05:48
  • I have looked at your code and found the error. At least managed to avoid crash on exit. Will post in few minutes. – Andrii Litvinov Apr 25 '17 at 08:35
  • @IvanStoev "that issue has nothing in common with EF, but the async function." - it so strange, because when I'm closing the app my background task (which create embedded db and connect to it) has finished it's work already (it's status is RanToCompletion). "Minimal, Complete, and Verifiable example" - please, see the update – whizzzkey Apr 25 '17 at 08:35
  • @whizzzkey Thanks for the sample project, but it does not reproduce on my machine. All I see is a little delay. May be someone else will be able to duplicate it, good luck. – Ivan Stoev Apr 25 '17 at 09:48

3 Answers3

4

In your connection string, you have specified a character set and enabled connection pooling:

FbConnectionStringBuilder builder = new FbConnectionStringBuilder
{
    …
    Charset = "WIN1251",
    …
    Pooling = true,
    …
};

The combination of these two settings appears to trigger the error; not in your own code, but in FirebirdSQL's. I have so far found three ways to resolve this issue. You can do either of these:

  1. Call the static FbConnection.ClearAllPools() method right before your application terminates (and leave connection pooling enabled):

    private static void AppExit(object sender, EventArgs e)
    {
        …
        FbConnection.ClearAllPools();
    }
    
  2. Disable connection pooling by setting Pooling = false.

  3. Since the error is triggered in fbintl.dll, which appears to be dealing with character sets / internationalization, you can simply omit the Charset connection string parameter (though I do not know what consequences this would have).

The last two suggestions are workarounds. I would probably go with option #1 as it seems to be cleanest, allows you to keep connection pooling enabled (which is usually a good thing), and specify the charset you need.

Note also that you might only ever see the exception if you run your application with a debugger attached. In production, the exception might well stay silent and go completely unnoticed.

stakx - no longer contributing
  • 83,039
  • 20
  • 168
  • 268
  • Great job with the investigation! It indeed solves the issue. I was suspecting open connection, but haven't though it was possible to disable pooling. – Andrii Litvinov Apr 25 '17 at 17:00
  • 1
    @AndriiLitvinov: I took a closer look at the FirebirdSQL ADO.NET source code and discovered the **`FbConnection.ClearAllPools()`** method. You can leave pooling enabled and call that method just before your application terminates, and it should resolve the issue as well. Also, that feels like a proper solution instead of one that just circumvents the problem. – stakx - no longer contributing Apr 25 '17 at 17:25
  • Good and detailed answer, I'm very grateful to you that you spent your time to solving my problem. – whizzzkey Apr 26 '17 at 08:21
  • @whizzzkey: Thank you! This was an interesting challenge. I guess I could've dug deeper (this issue would probably warrant filing a bug report with the FirebugSQL team) but for practical purposes, I guess it'll do. :) – stakx - no longer contributing Apr 26 '17 at 08:39
1

Your exception handling shoud work except in 2 cases, stack overflow exceptions and memory exceptions. In this cases the behaviour should be the behaviour you described (system message "application has stopped working").
About stack overflow exceptions, with EF happens quite often when you serialize entities (json, xml, ...) with lazy load enabled. Are you serializing entities during exit?

If this is not your case you could check other two things:

  • do you ever detach the two event handlers?
  • are you causing exceptions in the exception handler?
bubi
  • 6,414
  • 3
  • 28
  • 45
  • Thanks for your response. A have no event handlers, all my code is so simple so I realy get stucked and confused with this problem. I have global unhandled exception handler in my app that doesn't catch anything - all working fine, but when I quit from app I get a this message. Plz see updates. – whizzzkey Mar 15 '17 at 08:43
1

It was a little tricky to debug you code _prepareAppTask = new TaskFactory().StartNew causes a race condition from time to time which in turn causes the exception I described in my original post.

Also it is not obvious that you throw and catch and exception behind the scenes when I tried to run DB code in main thread which caused unexpected behavior and made me thing the it solved the issue.

Other than that you I don't see any critical issues in your code which could lead to the error in question. It seems that either firebird itself or EF provider causes the issue on application shutdown. It has nothing to do with sync or async code - nothing like that. I was able to reproduce it simply running the console app.

App crashes on exit with Faulting module name: fbintl.DLL only if DB connection was created and DB was accessed by code. The answer to Faulting module what does this mean and why does this happen? makes me think that the issue is either with firebase or with EF provider.

Have you tried other ways to connect to firebase?

And if you only need to get rid of that nasty exception here is a hack that worked for me:

private static void AppExit(object sender, EventArgs e)
{
    ...
    // To ensure pending DB operations are processed. Not sure that's needed.
    int timeout = 1000;
    Thread.Sleep(timeout);
    Process.GetCurrentProcess().Kill();
}

Killing the process right before it exits prevents the error to show up.

Community
  • 1
  • 1
Andrii Litvinov
  • 12,402
  • 3
  • 52
  • 59