【问题标题】:Large VIDEO File Upload using Httpclient does not work on Xamarin.Android使用 Httpclient 上传大型视频文件在 Xamarin.Android 上不起作用
【发布时间】:2018-08-15 20:57:11
【问题描述】:

任何帮助或见解将不胜感激。

我设法获得的是该问题与 HTTPS 有关,因为我能够在发布到 HTTP 端点时收到 200 回复,类似于以下线程 here

目前很难解决以下问题:

我正在使用 AndroidClientHandler HttpClient 实现以及用于 SSL/TLS 实现的 NativeTLS 1.2+

当我在我的应用上录制超过 1 分钟或大于 20MB 的视频时,我收到以下错误: "无法访问已处置的对象。\n对象名称: 'System.Net.Sockets.NetworkStream'。”

方法如下

    public async Task<HttpResponseMessage> UploadVideo(string endPoint)
    {
        HttpResponseMessage responseMessage = null;
        try
        {
            //Stopwatch stopWatch = new Stopwatch();

            IList<KeyValuePair<string, string>> formFields = new List<KeyValuePair<string, string>>();
            messageHandlerService = Mvx.Resolve<IMessageHandlerService>();

            //Declare a scope whereby you can use resources and once you leave the scope the resources are disposed of.
            using (StreamReader reader = pathService.GetStreamReaderByPlatform())
            {
                client = await MyHttpClient.GetClientAsync();
                client.Timeout = TimeSpan.FromSeconds(500);

                var bytes = default(byte[]);
                using (var memstream = new MemoryStream())
                {
                    reader.BaseStream.CopyTo(memstream);
                    bytes = memstream.ToArray();

                    using (var content = new MultipartFormDataContent())
                    {
                        var fileContent = new ByteArrayContent(bytes);
                        fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
                        {
                            FileName = ".mp4",
                        };
                        content.Add(fileContent);
                        content.Add(EncodeFields(formFields));

                        await Policy.Handle<TimeoutException>()
                          .Or<HttpRequestException>()
                          .Or<IOException>()
                          .OrResult<HttpResponseMessage>(r => httpStatusCodesToRetry.Contains(r.StatusCode))
                          .WaitAndRetryAsync
                          (retryCount: 3,
                           sleepDurationProvider: retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)),
                           onRetry: (ex, time) =>
                           {
                               Debug.WriteLine($"Something went wrong: {ex.Exception.Message}, retrying...");
                           }).ExecuteAsync(async () =>
                        {
                            Debug.WriteLine($"Trying to fetch remote data...");
                            responseMessage = await client.PostAsync(endPoint, content);
                            return responseMessage;
                        });
                    }
                }
            }
        }
        catch (WebException webx)
        {

            if (responseMessage == null)
            {
                responseMessage = new HttpResponseMessage();
            }

            responseMessage.StatusCode = HttpStatusCode.InternalServerError;
            responseMessage.ReasonPhrase = string.Format("RestHttpClient.SendRequest failed: {0}", webx);
        }
        catch (Exception ex)
        {
            if (responseMessage == null)
            {
                responseMessage = new HttpResponseMessage();
            }

            responseMessage.StatusCode = HttpStatusCode.InternalServerError;
            responseMessage.ReasonPhrase = string.Format("RestHttpClient.SendRequest failed: {0}", ex);
        }

        return responseMessage;
    }

下面是堆栈跟踪:

" 在 System.Net.WebConnectionStream.EndWrite (System.IAsyncResult r) [0x000b8] in :0 \n 在 System.IO.Stream+c.b__53_1 (System.IO.Stream 流,System. IAsyncResult asyncResult) [0x00000] in :0 \n at (wrapper delegate-invoke) System.Func3[System.IO.Stream,System.IAsyncResult,System.Threading.Tasks.VoidTaskResult].invoke_TResult_T1_T2(System.IO.Stream,System.IAsyncResult)\n at System.Threading.Tasks.TaskFactory1+FromAsyncTrimPromise1[TResult,TInstance].Complete (TInstance thisRef, System.Func3[T1,T2,TResult] endMethod, System.IAsyncResult asyncResult, System.Boolean requiresSynchronization) [0x00000] in :0 \n--- 从先前引发异常的位置结束堆栈跟踪 ---\n 在 System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in :0 \n 在 System. Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task 任务) [0x0003e] in :0 \n System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task 任务) [0x00028] 在: 0 \n 在 System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task 任务) [0x00008] in :0 \n 在 System.Runti me.CompilerServices.ConfiguredTaskAwaitable+ConfiguredTaskAwaiter.GetResult () [0x00000] in :0 \n 在 System.Net.Http.MultipartContent+d__8.MoveNext () [0x0025d] in :0 \n--- 堆栈结束从先前引发异常的位置跟踪 ---\n 在 System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in :0 \n 在 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.任务任务)[0x0003e] in :0 \n System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task 任务)[0x00028] in :0 \n System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd ( System.Threading.Tasks.Task task) [0x00008] in :0 \n System.Runtime.CompilerServices.ConfiguredTaskAwaitable+ConfiguredTaskAwaiter.GetResult () [0x00000] in :0 \n System.Net.Http.HttpClientHandler+d__64。 MoveNext () [0x0036e] in :0 \n--- 堆栈跟踪从 pre抛出异常的位置 ---\n 在 System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in :0 \n 在 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task 任务) [0x0003e] in :0 \n System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task 任务) [0x00028] in :0 \n System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System. Threading.Tasks.Task 任务)[0x00008] in :0 \n 在 System.Runtime.CompilerServices.ConfiguredTaskAwaitable1+ConfiguredTaskAwaiter[TResult].GetResult () [0x00000] in &lt;f32579baafc1404fa37ba3ec1abdc0bd&gt;:0 \n at System.Net.Http.HttpClient+&lt;SendAsyncWorker&gt;d__49.MoveNext () [0x000ca] in &lt;996a681f30a44cd685a4da54e11956e2&gt;:0 \n--- End of stack trace from previous location where exception was thrown ---\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in &lt;f32579baafc1404fa37ba3ec1abdc0bd&gt;:0 \n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) [0x0003e] in &lt;f32579baafc1404fa37ba3ec1abdc0bd&gt;:0 \n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) [0x00028] in &lt;f32579baafc1404fa37ba3ec1abdc0bd&gt;:0 \n at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) [0x00008] in &lt;f32579baafc1404fa37ba3ec1abdc0bd&gt;:0 \n at System.Runtime.CompilerServices.TaskAwaiter1 …

【问题讨论】:

  • 你能curl把同样大小的文件放到你的网络服务器上吗?如果是这样,您是否在程序中尝试过其他基于 http 的客户端,例如 okhttp?
  • 将大量内容复制到内存流中似乎不太理想。
  • 我很惊讶他在转换了这么大的内存流后并没有出现 OOM。
  • 继其他 cmets 之后,很明显旧的低堆大小 android 内存不足,无法保存您的大文件,并且您的对象已从内存中释放/清除。考虑一个解决方案,例如 snot 加载整个文件但在发送时拆分内存块。
  • 谢谢大家的cmets,我一直在考虑分块上传,我相信这可能是最好的路线。我

标签: android xamarin xamarin.android httpclient


【解决方案1】:

我已通过在 Xamarin.Android 的项目构建设置中设置一些标志来解决该问题。

Docs 的建议相反,设置以下配置允许我使用 HTTPS 将文件发布到我的服务器。使用原生 TLS 1.2+ 上传大于 20MB 时会崩溃……是的,我们的服务器支持 TLS 1.2

【讨论】:

    猜你喜欢
    • 2017-03-09
    • 2017-11-07
    • 2017-06-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-27
    • 2013-12-01
    • 2021-09-02
    相关资源
    最近更新 更多