【问题标题】:Embedded server application has stopped working after exit嵌入式服务器应用程序在退出后停止工作
【发布时间】:2017-08-05 12:49:09
【问题描述】:

我有一个在 firebird 数据库中存储一些数据的应用程序。我正在使用嵌入式 firebird 服务器和 EntityFramework,并且一切正常,但是当我通过表单上的 x 按钮关闭我的应用程序时,我收到一条 Windows 系统消息“应用程序已停止工作”,我无法捕捉到这个异常。我的应用中有一个 UnhandledExceptionHandler :

// 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());

但这种异常从未被它捕获。所以我去了 Windows 事件日志,在那里找到了这个错误事件的 xml 视图:

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

如您所见,当应用程序已关闭时 fbintl.DLL 出现问题。那么我怎样才能得到关于这个问题的更详细的描述呢?

UPD 我让应用程序更短以检测我的问题的原因 - 现在只有此 EF 代码在应用程序关闭之前运行

 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);
        }
    }

FirebirdDbContext 在哪里:

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();
        }
    }
}

而连接参数是

  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();
    }

2017 年 4 月 25 日新更新

我用 firebird 嵌入式数据库制作了一个简单的应用程序来演示错误。你可以找到它here

应用程序创建一个firebird嵌入式数据库并在后台线程(任务TPL)中连接到它,工作完成后(_bgTask.Status == TaskStatus.RanToCompletion)你关闭应用程序并得到错误。

【问题讨论】:

  • 您使用的是哪个版本的 Firebird Embedded?我不完全确定,但我相信一些旧版本在某些情况下没有正确清理,例如tracker.firebirdsql.org/browse/CORE-5117(在 2.5.6 中修复)
  • @MarkRotteveel 我正在使用 firebird 1.5.6 和其他应用程序 firebird 2.5.6 - 两者都发生错误
  • 在应用程序关闭时运行异步代码可能无法按预期工作。尝试从 GetAutoAnswerTemplate 中删除所有异步内容(使其同步),看看是否有帮助(只是为了诊断问题,而不是作为最终解决方案)。
  • 也尝试订阅 TaskScheduler.UnobservedTaskException 看看它是否在那里结束。您拥有哪个 .NET Framework 版本?
  • 我怀疑这个问题与 EF 没有任何共同之处,而是 async 函数。这就是为什么查看用法很重要的原因——该函数在何处以及如何调用。换句话说,minimal reproducible example.

标签: c# entity-framework unhandled-exception firebird-embedded


【解决方案1】:

在您的连接字符串中,您已经指定了一个字符集并启用了连接池:

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

这两个设置的组合似乎会触发错误;不是在您自己的代码中,而是在 FirebirdSQL 中。到目前为止,我已经找到了三种方法来解决这个问题。您可以执行以下任一操作:

  1. 在您的应用程序终止之前调用静态 FbConnection.ClearAllPools() 方法(并启用连接池):

    private static void AppExit(object sender, EventArgs e)
    {
        …
        FbConnection.ClearAllPools();
    }
    
  2. 通过设置Pooling = false禁用连接池

  3. 由于错误是在fbintl.dll 中触发的,这似乎是在处理字符集/国际化,您可以简单地省略Charset 连接字符串参数(虽然我没有知道这会产生什么后果)。

最后两个建议是解决方法。我可能会选择选项 #1,因为它似乎最干净,允许您保持启用连接池(这通常是一件好事),并指定您需要的字符集。

另请注意,如果您运行带有调试器的应用程序,您可能只会看到异常。在生产环境中,该异常很可能会保持沉默并且完全被忽视。

【讨论】:

  • 调查工作做得很好!它确实解决了这个问题。我怀疑打开了连接,但还没有禁用池。
  • @AndriiLitvinov:我仔细查看了 FirebirdSQL ADO.NET 源代码,发现了 FbConnection.ClearAllPools() 方法。您可以启用池并在应用程序终止之前调用该方法,它也应该解决问题。此外,这感觉像是一种适当的解决方案,而不是仅仅规避问题的解决方案。
  • 好详细的回答,非常感谢您花时间解决我的问题。
  • @whizzzkey:谢谢!这是一个有趣的挑战。我想我可以深入挖掘(这个问题可能需要向 FirebugSQL 团队提交错误报告)但出于实际目的,我想它会做。 :)
【解决方案2】:

调试你的代码有点棘手 _prepareAppTask = new TaskFactory().StartNew 不时会导致竞争条件,这反过来又会导致我在原始帖子中描述的异常。

当我试图在主线程中运行数据库代码时,你在幕后抛出和捕获异常并不明显,这导致了意外的行为,让我觉得它解决了这个问题。

除此之外,我在您的代码中看不到任何可能导致相关错误的严重问题。似乎火鸟本身或 EF 提供程序会导致应用程序关闭时出现问题。它与同步或异步代码无关 - 不是那样的。我只需运行控制台应用程序即可重现它。

应用程序在退出时崩溃,错误模块名称:fbintl.DLL 仅在创建 DB 连接并且代码访问 DB 的情况下。 Faulting module what does this mean and why does this happen? 的答案让我认为问题出在 firebase 或 EF 提供程序上。

您是否尝试过其他方式连接到 Firebase?

如果你只需要摆脱这个讨厌的异常,这里有一个对我有用的技巧:

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();
}

在进程退出之前将其终止可以防止错误出现。

【讨论】:

  • 非常感谢您的回答,我会尝试并稍后提供结果。(在 2-3 小时内)
  • 我已删除 progessDialog - 没有任何变化
【解决方案3】:

您的异常处理应该工作,除了 2 种情况,堆栈溢出异常和内存异常。在这种情况下,行为应该是您描述的行为(系统消息“应用程序已停止工作”)。
关于堆栈溢出异常,当您序列化启用延迟加载的实体(json、xml、...)时,EF 经常发生。您是否在退出期间序列化实体?

如果这不是你的情况,你可以检查其他两件事:

  • 您是否曾经分离过这两个事件处理程序?
  • 您是否在异常处理程序中引发了异常?

【讨论】:

  • 感谢您的回复。 A 没有事件处理程序,我所有的代码都非常简单,所以我真的被这个问题卡住并感到困惑。我的应用程序中有全局未处理的异常处理程序,它没有捕获任何东西 - 一切正常,但是当我从应用程序退出时,我收到一条消息。请查看更新。
猜你喜欢
  • 2017-06-11
  • 2013-01-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-20
  • 1970-01-01
  • 2016-02-07
相关资源
最近更新 更多