SqlBulkCopy.WriteToServer()继续“连接已关闭”

时间:2014-06-17 20:21:44

标签: c# sql-server sqlbulkcopy

这对我来说毫无意义,但也许有眼睛敏锐的人可以发现问题。

我有一个使用FileSystemWatcher的Windows服务。它处理一些文件并将数据上传到MSSQL数据库。它在我的机器上完全正常工作 - 与Visual Studio分离(即不调试)并作为服务运行。如果将这个已编译的代码复制到我们的服务器,并让它指向同一个数据库,甚至是相同的文件(!),我每次都会收到此错误:

System.InvalidOperationException: Invalid operation. The connection is closed.
   at System.Data.SqlClient.SqlConnection.GetOpenTdsConnection()
   at System.Data.SqlClient.SqlBulkCopy.CopyBatchesAsyncContinuedOnError(Boolean cleanupParser)
   at System.Data.SqlClient.SqlBulkCopy.<>c__DisplayClass30.<CopyBatchesAsyncContinuedOnSuccess>b__2c()
   at System.Data.SqlClient.AsyncHelper.<>c__DisplayClass9.<ContinueTask>b__8(Task tsk)

我已尝试将本地代码指向服务器的文件,但它运行正常。 .Net 4.5.1在两台机器上。服务都在同一个域用户下运行。令人费解。也许我对SqlBulkCopy.WriteToServerAsync()有些不了解的东西?它会自动共享连接吗?它是否在通话之间关闭?这是相关的代码:

private static void ProcessFile(FileInfo fileInfo)
{
    using (var bulkCopy = new SqlBulkCopy("Data Source=myserver;Initial Catalog=mydb;Persist Security Info=True;User ID=myusr;Password=mypwd;")
    using (var objRdr = ObjectReader.Create(ReadLogFile(fileInfo)
                                    .Where(x => !string.IsNullOrEmpty(x.Level)),
                                         "Id", "AppId", "AppDomain", "AppMachine",
                                         "LocalDate", "UtcDate", "Thread", "Level", "Logger", "Usrname",
                                         "ClassName", "MethodName", "LineNo", "Message", "Exception",
                                         "StackTrace", "Properties"))
    {
        bulkCopy.DestinationTableName = "EventLog";
        bulkCopy.BulkCopyTimeout = 600;
        bulkCopy.EnableStreaming = true;
        bulkCopy.BatchSize = AppConfig.WriteBatchSize;
        bulkCopy.WriteToServerAsync(objRdr).ContinueWith(t =>
            {
                if (t.Status == TaskStatus.Faulted)
                {
                    CopyToFailedDirectory(fileInfo);
                    _log.Error(
                        string.Format(
                            "Error copying logs to database for file {0}. File has been copied to failed directory for inspection.",
                            fileInfo.FullName), t.Exception.InnerException ?? t.Exception);
                    Debug.WriteLine("new handle error {0}",
                                    (t.Exception.InnerException ?? t.Exception).Message);
                }
                if (t.Status == TaskStatus.RanToCompletion)
                {
                    _log.InfoFormat("File {0} logs have been copied to database.", fileInfo.FullName);
                    Debug.WriteLine("Yay, finished {0}!", fileInfo.Name);
                }
                // if this is the last one, delete the original file
                if (t.Status == TaskStatus.Faulted || t.Status == TaskStatus.RanToCompletion)
                {
                    Debug.WriteLine("deleting file {0}", fileInfo.Name);
                    PurgeFile(fileInfo);
                }
            });
    }
}

如果你问的话,请记下一些笔记:

  • ObjectReader是FastMember IDataReader实现。疯狂快。它使用您列出的属性将文件读入自定义对象。
  • 它会为每个文件抛出错误。
  • 同样,这可以在我的机器上运行,既可以作为服务也可以作为控制台应用程序。我甚至让它在服务器上运行一次。它抛出错误而再也没有工作过。

有什么想法吗?

3 个答案:

答案 0 :(得分:5)

看起来像是异步的问题。

如果我错了,请告诉我,但我注意到您在使用声明中使用了SqlBulkCopyObjectReader这很好,但是,您正在异步进行所有处理。一旦你调用它并开始工作,你的using语句就会处理你的对象,这也会破坏你的连接。

奇怪的是,它听起来有时会起作用,但也许它只是在那时成为一种竞争条件。

答案 1 :(得分:0)

这让我觉得它是SqlBulkCopy实现中的一个错误。如果同时在单独的任务中并行运行(大量)批量副本,禁用网络连接然后触发完整的垃圾回收,您将可靠地在GC的终结器线程上抛出此异常。这是完全不可避免的。

这不应该发生,因为您继续执行$('#selectChannel').val(data.channel); $('#fromDate').val(data.fromDate); 任务并处理故障。但是在实施过程中,出错时他们会开始一项新的任务,他们不会继续或等待。

这似乎仍然是.NET 4.6.2中的一个错误。

我能看到的唯一解决方案是订阅WriteToServerAsync并在stacktrace中查找标识问题的内容。顺便说一句,这不是一个修复,它是一个黑客。

答案 2 :(得分:0)

晚点把这个扔到这里,但是我当时认为SqlBulkCopy是同样的问题。尝试了其他答案中的某些步骤,但是没有运气。在我的情况下,结果表明实际错误是由于数据中的字符串超出了varchar列之一的最大长度而引起的,但是由于某种原因,我遇到的唯一错误是有关关闭连接的错误。

奇怪的是,我的同事尝试了同样的事情,并收到有关varchar超出范围的实际错误消息。因此,我们修复了数据,一切正常,但是如果由于这个错误而您在这里,而其他任何事情都没有,那么您可能要开始在数据中寻找其他问题。