【问题标题】:C# + Mono: Error while running Azure-Storage SDKC# + Mono:运行 Azure-Storage SDK 时出错
【发布时间】:2017-08-08 18:27:15
【问题描述】:

我有一个在 Windows 环境下运行良好的应用程序。使用 C# 4.6.1 编写并使用 Azure 存储上传\下载 blob 的应用程序。

我想在 linux ubuntu 服务器 (v16) 上运行相同的应用程序。在服务器上安装单声道后,我尝试运行该应用程序。程序异常崩溃。

所以,我添加了日志,发现问题来自 Azure-Storage SDK(v7.0.0,通过 nu-get 安装)。

这是我的相关代码:

CloudBlockBlob blob = container.GetBlockBlobReference(string.Join("", blob_path));
using (MemoryStream ms = new MemoryStream())
{
    blob.DownloadToStream(ms); // <--- BOOM
    //...
}

这是我在使用 Mono 运行时遇到的异常:

Microsoft.WindowsAzure.Storage.StorageException: read failed 
---> System.IO.IOException: read failed 
---> System.InvalidOperationException: Operation is not valid due to the current state of the object.
  at Mono.Net.Security.MobileAuthenticatedStream.CheckThrow (System.Boolean authSuccessCheck) [0x0001b] in <2b0d86369d72459baed0cee98a8e578a>:0 
  at Mono.Net.Security.MobileAuthenticatedStream.get_Context () [0x00000] in <2b0d86369d72459baed0cee98a8e578a>:0 
  at Mono.Net.Security.MobileAuthenticatedStream.ProcessRead (Mono.Net.Security.AsyncProtocolRequest asyncRequest, Mono.Net.Security.AsyncOperationStatus status) [0x00011] in <2b0d86369d72459baed0cee98a8e578a>:0 
  at Mono.Net.Security.AsyncProtocolRequest.ProcessOperation (Mono.Net.Security.AsyncOperationStatus status) [0x0006b] in <2b0d86369d72459baed0cee98a8e578a>:0 
  at Mono.Net.Security.AsyncProtocolRequest.ProcessOperation () [0x0000d] in <2b0d86369d72459baed0cee98a8e578a>:0 
  at Mono.Net.Security.AsyncProtocolRequest.StartOperation () [0x00000] in <2b0d86369d72459baed0cee98a8e578a>:0 
   --- End of inner exception stack trace ---
  at Mono.Net.Security.MobileAuthenticatedStream.EndReadOrWrite (System.IAsyncResult asyncResult, Mono.Net.Security.AsyncProtocolRequest& nestedRequest) [0x00055] in <2b0d86369d72459baed0cee98a8e578a>:0 
  at Mono.Net.Security.MobileAuthenticatedStream.EndRead (System.IAsyncResult asyncResult) [0x00000] in <2b0d86369d72459baed0cee98a8e578a>:0 
  at System.Net.WebConnection.EndRead (System.Net.HttpWebRequest request, System.IAsyncResult result) [0x000d4] in <2b0d86369d72459baed0cee98a8e578a>:0 
  at System.Net.WebConnectionStream.EndRead (System.IAsyncResult r) [0x000af] in <2b0d86369d72459baed0cee98a8e578a>:0 
  at Microsoft.WindowsAzure.Storage.Core.ByteCountingStream.EndRead (System.IAsyncResult asyncResult) [0x00000] in <1a6da444611441028237826045bb8126>:0 
  at Microsoft.WindowsAzure.Storage.Core.Util.StreamExtensions.WriteToSync[T] (System.IO.Stream stream, System.IO.Stream toStream, System.Nullable`1[T] copyLength, System.Nullable`1[T] maxLength, System.Boolean calculateMd5, System.Boolean syncRead, Microsoft.WindowsAzure.Storage.Core.Executor.ExecutionState`1[T] executionState, Microsoft.WindowsAzure.Storage.Core.Util.StreamDescriptor streamCopyState) [0x002c6] in <1a6da444611441028237826045bb8126>:0 
  at Microsoft.WindowsAzure.Storage.Core.Executor.Executor.ExecuteSync[T] (Microsoft.WindowsAzure.Storage.Core.Executor.RESTCommand`1[T] cmd, Microsoft.WindowsAzure.Storage.RetryPolicies.IRetryPolicy policy, Microsoft.WindowsAzure.Storage.OperationContext operationContext) [0x003c7] in <1a6da444611441028237826045bb8126>:0 
   --- End of inner exception stack trace ---
  at Microsoft.WindowsAzure.Storage.Core.Executor.Executor.ExecuteSync[T] (Microsoft.WindowsAzure.Storage.Core.Executor.RESTCommand`1[T] cmd, Microsoft.WindowsAzure.Storage.RetryPolicies.IRetryPolicy policy, Microsoft.WindowsAzure.Storage.OperationContext operationContext) [0x006b5] in <1a6da444611441028237826045bb8126>:0 
  at Microsoft.Wind… Read more                        
  at Microsoft.WindowsAzure.Storage.Core.ByteCountingStream.EndRead (System.IAsyncResult asyncResult) [0x00000] in <1a6da444611441028237826045bb8126>:0 
  at Microsoft.WindowsAzure.Storage.Core.Util.StreamExtensions.WriteToSync[T] (System.IO.Stream stream, System.IO.Stream toStream, System.Nullable`1[T] copyLength, System.Nullable`1[T] maxLength, System.Boolean calculateMd5, System.Boolean syncRead, Microsoft.WindowsAzure.Storage.Core.Executor.ExecutionState`1[T] executionState, Microsoft.WindowsAzure.Storage.Core.Util.StreamDescriptor streamCopyState) [0x002c6] in <1a6da444611441028237826045bb8126>:0
  at Microsoft.WindowsAzure.Storage.Core.Executor.Executor.ExecuteSync[T] (Microsoft.WindowsAzure.Storage.Core.Executor.RESTCommand`1[T] cmd, Microsoft.WindowsAzure.Storage.RetryPolicies.IRetryPolicy policy, Microsoft.WindowsAzure.Storage.OperationContext operationContext) [0x003c7] in <1a6da444611441028237826045bb8126>:0 
   --- End of inner exception stack trace ---
  at Microsoft.WindowsAzure.Storage.Core.Executor.Executor.ExecuteSync[T] (Microsoft.WindowsAzure.Storage.Core.Executor.RESTCommand`1[T] cmd, Microsoft.WindowsAzure.Storage.RetryPolicies.IRetryPolicy policy, Microsoft.WindowsAzure.Storage.OperationContext operationContext) [0x006b5] in <1a6da444611441028237826045bb8126>:0 
  at Microsoft.WindowsAzure.Storage.Blob.CloudBlob.DownloadRangeToStream (System.IO.Stream target, System.Nullable`1[T] offset, System.Nullable`1[T] length, Microsoft.WindowsAzure.Storage.AccessCondition accessCondition, Microsoft.WindowsAzure.Storage.Blob.BlobRequestOptions options, Microsoft.WindowsAzure.Storage.OperationContext operationContext) [0x00033] in <1a6da444611441028237826045bb8126>:0 
  at Microsoft.WindowsAzure.Storage.Blob.CloudBlob.DownloadToStream (System.IO.Stream target, Microsoft.WindowsAzure.Storage.AccessCondition accessCondition, Microsoft.WindowsAzure.Storage.Blob.BlobRequestOptions options, Microsoft.WindowsAzure.Storage.OperationContext operationContext) [0x00000] in <1a6da444611441028237826045bb8126>:0 
  at ***.DownloadFile (System.Uri url, System.IO.FileInfo file) [0x000e8] in <1a85ad8f477c4d6f8a3af08c9e99e976>:0 
  at ***.TimedCache+<Add>d__32.MoveNext () [0x00160] in <1a85ad8f477c4d6f8a3af08c9e99e976>:0 
Request Information
RequestID:2025b933-0001-0031-2325-10951e000000
RequestDate:Tue, 08 Aug 2017 09:08:58 GMT
StatusMessage:Partial Content

Linux 机器在 Google-Cloud 下运行。解决这个问题的一个方向是 Goolge-Cloud 防火墙。可能是防火墙阻止了与 Azure-Storage 的通信?

我的代码基本上是从存储中下载一个 blob 并将其保存在本地。奇怪的是,当我检查保存文件的目录时,我可以找到一些文件。什么意思,它在某些时候起作用。

如何解决问题?

更新

根据@Amor,我试图了解问题出在哪里。我们有两种选择:

  • 问题出在 C# 代码或 Mono 上。
  • 问题出在环境上(Linux \ google-cloud \ ...)

我在this page 上下载了名为“Storage_REST_CS.zip”的代码。根据需要更新代码(插入我的凭据)并在 Windows 环境中对其进行测试 - 运行良好。我拿了二进制文件并将它们移动到我的 Linux 机器上进行测试。我得到了错误:

System.Net.WebException: The remote server returned an error: (403) Server failed to authenticate the request. Make sure the value of Authorization headers formed correctly including the signature.
    at StorageSampleREST.RESTHelper.Retry[T] (StorageSampleREST.RESTHelper+RetryDelegate`1[T] del, System.Int32 numberOfRetries, System.Int32 msPause) [0x0001d] in <033ea4d1a16740f3b711001b7c2f09f5>:0 
    at StorageSampleREST.RESTHelper.Retry[T] (StorageSampleREST.RESTHelper+RetryDelegate`1[T] del) [0x00001] in <033ea4d1a16740f3b711001b7c2f09f5>:0 
    at StorageSampleREST.BlobHelper.ListContainers () [0x00001] in <033ea4d1a16740f3b711001b7c2f09f5>:0 
    at StorageSampleREST.Program.TestBlobStorage () [0x00023] in <033ea4d1a16740f3b711001b7c2f09f5>:0

现在我试图了解问题出在哪里 - 在我的代码 (c#) 或环境(Linux - Google 云)中。所以我提取了执行的 HTTP 请求(在 Mono 上失败)并尝试直接使用 cURL 运行它:

curl -i -H "x-ms-date: Wed, 09 Aug 2017 09:03:46 GMT
x-ms-version: 2009-09-19
Authorization: SharedKey userfiles:***" -X GET https://***.blob.core.windows.net/?comp=list

结果是 200 OK。什么意思,这不是任何防火墙、Linux 环境或连接的问题。

现在,重点应该放在 Mono 设置上,因为使用 cURL 执行相同的 HTTP 请求已成功完成 (200)。这不取决于我的具体代码,因为上面提到的示例代码也会发生类似的行为。

谢谢。

【问题讨论】:

    标签: c# linux mono google-cloud-platform azure-blob-storage


    【解决方案1】:

    Azure 存储客户端 SDK 将使用 Https 与存储服务器通信,您的客户端将验证从服务器端收到的证书。迁移到 MONO 后,请在代码顶部添加以下代码以验证证书。

    ServicePointManager.ServerCertificateValidationCallback = MyRemoteCertificateValidationCallback;
    
    public static bool  MyRemoteCertificateValidationCallback(Object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
    {
        bool isOk = true;
        // If there are errors in the certificate chain,
        // look at each error to determine the cause.
        if (sslPolicyErrors != SslPolicyErrors.None)
        {
            for (int i = 0; i < chain.ChainStatus.Length; i++)
            {
                if (chain.ChainStatus[i].Status == X509ChainStatusFlags.RevocationStatusUnknown)
                {
                    continue;
                }
                chain.ChainPolicy.RevocationFlag = X509RevocationFlag.EntireChain;
                chain.ChainPolicy.RevocationMode = X509RevocationMode.Online;
                chain.ChainPolicy.UrlRetrievalTimeout = new TimeSpan(0, 1, 0);
                chain.ChainPolicy.VerificationFlags = X509VerificationFlags.AllFlags;
                bool chainIsValid = chain.Build((X509Certificate2)certificate);
                if (!chainIsValid)
                {
                    isOk = false;
                    break;
                }
            }
        }
        return isOk;
    }
    

    【讨论】:

    • 没有解决问题。同样的行为。
    • 您是否尝试过使用 Azure 存储 REST API 并检查它是否适用于您的环境?您可以从此链接下载并使用使用 Azure 存储 REST API 的示例代码。 azurestoragesamples.codeplex.com/releases/view/61325
    • 该问题与生成 SAS 的逻辑有关。请使用从 Azure 门户生成的固定 SAS。还请添加我回复中提供的服务器证书验证码。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-07-21
    • 1970-01-01
    • 1970-01-01
    • 2016-07-30
    • 2020-01-31
    • 2013-05-18
    • 1970-01-01
    相关资源
    最近更新 更多