我对某个项目有一个简单的架构,有点像这样:
99%的情况下都有效。文件可以在缓存中找到或下载,然后使用第三方代码打开,然后以精美的视图呈现给用户。
但是,我可以复制一系列奇怪的情况,这会导致我的生产服务器彻底崩溃。
他们如下:
我理解我在使用不安全的库时遇到了一些问题,但最奇怪的是,如果我再次尝试,该文件现在将在缓存中,因为Azure第一次正确使用,Azure不是'点击,文件将成功打开。
第三方库实际上将从Azure下载的文件视为已损坏,但是当完全相同的代码尝试打开完全相同的文件而没有Azure参与时,它就没有问题。
所以我最初指责Azure,也许我没有正确关闭文件。我已经检查过,我用来获取文件的文件流肯定是关闭的(它包含在using语句中)。
代码在下面,(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);
}
}
Weirder仍然,我重复我的测试,这次,在崩溃后,我从缓存中删除文件,以便再次点击Azure。它是,并且文件打开而不会导致崩溃。
所以它似乎只是第一次打开从Azure下载的文件 - 我只需通过回收应用程序池就可以导致错误。
有没有人对我如何调试这个有任何建议?我无法在我的本地开发机器上复制。
编辑:Richard Turner的反馈意见
我不相信blob检索代码是导致异常的原因。这样做的原因是,如果Web应用程序崩溃,这是在文件下载后。我甚至可以验证文件没有损坏,因为我可以在后续重试时打开它。
你对'不安全'的说法是完全正确的 - 我有执行PInvoke的包装代码 - 然而,它没有实现IDisposable,这是我将立即研究的内容。至于表现,此时我并不担心。
关于重新组织我的代码,我描述的“缓存”实际上是磁盘上的一组文件,所以本质上我已经有了你推荐的结构。第三方库只接受文件路径作为输入,因此我必须遵循该路由。
回答你的最后问题:
将blob作为流读取是我能看到的唯一可读方式吗?我没有看到任何API方法将其作为byte []或其他任何内容获取。
FileStream不需要是读/写,但改变它并没有改善。
答案 0 :(得分:0)
你应该对这类事情使用异常处理:
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
}
答案 1 :(得分:0)
由于你没有发帖,很难确定出了什么问题 例如,足够的代码可以理解你的样子 实例化/销毁第三方组件的实例以及如何实例化 你将数据传递给所说的组件。
但是,这里有几点需要考虑:
默契是对的:你的应用程序正在崩溃,因为它会抛出未处理的异常。假设与存储服务交互的任何操作都将失败。如果它们还没有,它们将会。因此,实现一个异常处理程序,它包装你的blob检索代码并在必要时实现重试语义。您可能希望添加ELMAH日志记录,以便记录应用代码中的崩溃和失败。
我不太明白第三方图书馆的“不安全”是什么意思。你的意思是“不安全”,因为它是你必须进入PInvoke的本地图书馆吗?
根据代码实例化/销毁第三方组件的方式,您可能会发现组件在使用后仍保留在内存中,并且可能会保留一些损坏/混淆的状态。如果您必须使用这样的组件,请考虑编写自己的PInvoke包装器,该包装器也支持IDisposable,并在完成后强制组件卸载。但请注意,这可能会导致性能损失。
另外需要考虑的一件事:也许你应该重新组织你的代码,以便第三方组件只从磁盘加载文件。
此外,您的代码中还有其他一些内容:
更新2013-02-28 @ 16:47太平洋标准时间 - 回复上面的KingCronus更新:
CloudBlobContainer.GetBlockBlobReference(...)返回CloudBlockBlob对象。 CloudBlockBlob对象具有DownloadByteArray(),DownloadText()的方法,重要的是 DownloadToFile() 。后一种API可能有助于完全缓解文件损坏问题!
完全可能的是,您正在进行PInvoking的本机组件可能会破坏IIS控制之外的运行进程。
如果因为输入数据(即文件)损坏而崩溃,那么考虑是否可以预处理数据以使其符合组件的要求。
如果组件继续崩溃,特别是因为其内部状态已损坏,您可能需要考虑通过创建承载组件实例的Windows服务来隔离IIS中的组件。如果失败,可以自动重启这样的服务。您可以通过WCF / NamedPipes /等与托管组件的服务进行通信。来回传递数据。但是,我认为我宁愿考虑完全替换组件,而不是像这样引入最后的机制!