C# 打开文件时,是什么导致我的服务器崩溃?

C# 打开文件时,是什么导致我的服务器崩溃?,c#,iis,azure,C#,Iis,Azure,我对某个项目有一个简单的架构,它有点像这样: try { //connection here } catch (Exception ex) { MessageBox.Show(ex.Message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error); // wil

我对某个项目有一个简单的架构,它有点像这样:

      try
        {
            //connection here
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
            // will give you the error if no connection and you can get an idea why it crashes
        }
  • 用户使用ASP.NET MVC请求文件
  • 检查所述文件的本地缓存,如果缓存中不存在该文件,则从Azure Blob存储中提取该文件
  • 至此,文件已明确位于我的服务器上,并且我知道路径
  • 我使用第三方库打开文件,为其提供路径,然后返回一个类结构,我使用该类结构为用户创建视图
  • 这是有效的,99%的时间。文件可以在缓存中找到,也可以下载,然后使用第三方代码打开,然后以漂亮的视图呈现给用户

          try
            {
                //connection here
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
                // will give you the error if no connection and you can get an idea why it crashes
            }
    
    然而,我可以复制一组奇怪的情况,这会导致我的生产服务器彻底崩溃

          try
            {
                //connection here
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
                // will give you the error if no connection and you can get an idea why it crashes
            }
    
    它们是:

          try
            {
                //connection here
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
                // will give you the error if no connection and you can get an idea why it crashes
            }
    
    • 在缓存中找不到文件
    • 文件是从Azure下载的
    • 第三方(不安全)库在打开文件时崩溃
    • 带着服务器
    我知道我在使用不安全的库时会遇到一些麻烦,但最奇怪的是,如果我再试一次,该文件现在将在缓存中,因为Azure在第一次使用时是正确的,Azure没有命中,文件将成功打开

          try
            {
                //connection here
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
                // will give you the error if no connection and you can get an idea why it crashes
            }
    
    第三方库本质上认为从Azure下载的文件已损坏,但当完全相同的代码尝试在没有Azure参与的情况下打开完全相同的文件时,它打开没有问题

          try
            {
                //connection here
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
                // will give you the error if no connection and you can get an idea why it crashes
            }
    
    所以我一开始责备Azure,也许我没有正确地关闭文件。我已经检查过了,我用来获取文件的filestream肯定被关闭了(它被包装在using语句中)

          try
            {
                //connection here
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
                // will give you the error if no connection and you can get an idea why it crashes
            }
    
    代码如下(forceRefresh是一个我可以设置为始终跳过本地缓存的标志)。路径设置为我的服务器上的某个位置~/tmp

    if (!File.Exists(path) || forceRefresh)
    {
       CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
       CloudBlobContainer blobContainer = blobClient.GetContainerReference("mycontainer");
    
       ICloudBlob blob = blobContainer.GetBlockBlobReference("myblob");
       using (var filestream = new FileStream(path,FileMode.Create,FileAccess.ReadWrite,FileShare.Read))
       {
            blob.DownloadToStream(filestream);
       }
    
    }
    
          try
            {
                //connection here
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
                // will give you the error if no connection and you can get an idea why it crashes
            }
    
    更奇怪的是,我重复了我的测试,这一次,在崩溃之后,我从缓存中删除了该文件,以便再次命中Azure。是的,文件打开时不会导致崩溃

          try
            {
                //connection here
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
                // will give you the error if no connection and you can get an idea why it crashes
            }
    
    因此,这似乎只是第一次打开从Azure下载的文件时发生的——我可以通过回收应用程序池按需导致错误

          try
            {
                //connection here
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
                // will give you the error if no connection and you can get an idea why it crashes
            }
    
    有人对我如何调试这个有什么建议吗?我无法在本地开发机器上复制

          try
            {
                //connection here
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
                // will give you the error if no connection and you can get an idea why it crashes
            }
    
    编辑:对Richard Turner反馈的回答

          try
            {
                //connection here
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
                // will give you the error if no connection and you can get an idea why it crashes
            }
    
    我不相信blob检索代码是导致异常的原因。原因是,如果web应用程序确实崩溃,这是在文件下载之后发生的。我甚至可以验证文件是否损坏,因为我可以在后续重试时打开它

          try
            {
                //connection here
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
                // will give you the error if no connection and you can get an idea why it crashes
            }
    
    你说的关于“不安全”的话完全正确——我有执行PInvoke的包装器代码——但是它没有实现IDisposable,这是我将立即研究的内容。至于表现,在这一点上我并不担心

          try
            {
                //connection here
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
                // will give you the error if no connection and you can get an idea why it crashes
            }
    
    关于重新组织我的代码,我描述的“缓存”实际上是磁盘上的一组文件,所以本质上我已经有了您推荐的结构。第三方库只接受一个文件路径作为输入,所以我必须遵循这个路径

          try
            {
                //connection here
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
                // will give you the error if no connection and you can get an idea why it crashes
            }
    
    在回答您最后的问题时:

          try
            {
                //connection here
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
                // will give you the error if no connection and you can get an idea why it crashes
            }
    
  • 以流的形式读取blob是我能看到的唯一可以读取它的方法吗?我没有看到任何API方法将其作为byte[]或任何其他形式

  •       try
            {
                //connection here
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
                // will give you the error if no connection and you can get an idea why it crashes
            }
    
  • FileStream不需要读/写,但更改它并没有改善情况

  •       try
            {
                //connection here
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
                // will give you the error if no connection and you can get an idea why it crashes
            }
    

    对于这类事情,您应该使用异常处理:

          try
            {
                //connection here
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
                // will give you the error if no connection and you can get an idea why it crashes
            }
    
    很难确定出哪里出了问题,因为你没有发布 例如,有足够的代码来理解 实例化/销毁第三方组件的实例以及如何 您正在将数据传递给所述组件

          try
            {
                //connection here
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
                // will give you the error if no connection and you can get an idea why it crashes
            }
    
    然而,这里有几件事需要考虑:

          try
            {
                //connection here
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
                // will give you the error if no connection and you can get an idea why it crashes
            }
    
    默契是对的:你的应用程序正在崩溃,因为它抛出了未处理的异常。假设与存储服务交互的任何操作都将失败。因此,实现一个异常处理程序来包装blob检索代码,并在必要时实现重试语义。您可能希望添加日志记录,以便在应用程序代码中记录崩溃和故障

          try
            {
                //connection here
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
                // will give you the error if no connection and you can get an idea why it crashes
            }
    
    我不太明白你所说的第三方图书馆“不安全”是什么意思。你的意思是“不安全”吗?因为这是一个你必须用PInvoke进入的本地库

          try
            {
                //connection here
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
                // will give you the error if no connection and you can get an idea why it crashes
            }
    
    根据代码实例化/销毁第三方组件的方式,您可能会发现该组件在使用后仍保留在内存中,并且可能会保持一些损坏/混乱的状态。如果您必须使用这样的组件,请考虑编写自己的PInvoke包装器,该包装器还支持IDISPOLISTABLE,并在完成该组件时强制卸载该组件。但是,请注意,这可能会导致性能命中

          try
            {
                //connection here
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
                // will give you the error if no connection and you can get an idea why it crashes
            }
    
    需要考虑的另一件事是:也许您应该稍微重新组织代码,以便第三方组件只从磁盘加载文件

          try
            {
                //connection here
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
                // will give you the error if no connection and you can get an idea why it crashes
            }
    
  • 如果文件不在磁盘上,请从Azure加载它(使用必要的异常处理程序包装操作)并将其存储在磁盘上
  • 从磁盘加载文件内容并传递到第三方组件
  • 此外,在代码中还有一些其他内容需要查看:

          try
            {
                //connection here
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
                // will give you the error if no connection and you can get an idea why it crashes
            }
    
  • 是否有任何理由将blob作为流而不是字节[]或字符串读取
  • 创建读/写文件流有什么原因吗?如果您没有写入流,请考虑以只读模式打开流。
  • 更新2013-02-28@16:47太平洋标准时间-回复KingCronus的上述更新:

          try
            {
                //connection here
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
                // will give you the error if no connection and you can get an idea why it crashes
            }
    
    GetBlockBlobReference(…)返回一个CloudBlockBlob对象。CloudBlockBlob对象具有方法,重要的是,。后一个API可能有助于完全缓解文件损坏问题

          try
            {
                //connection here
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
                // will give you the error if no connection and you can get an idea why it crashes
            }
    
    它是