Search code examples
c#entity-frameworkunhandled-exceptionfirebird-embedded

Embedded server application has stopped working after exit


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.


Solution

  • 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.