C# HttpClient PUT

本文关键字:PUT HttpClient | 更新日期: 2023-09-27 18:08:10

由于某种原因,我下面的代码过去可以工作,现在却引发了一个异常:

public static async Task<string> HttpPut(string inUrl, string inFilePath)
    {
        using (var handler = new HttpClientHandler
        {
            AllowAutoRedirect = false
        })
        {
            using (var client = new HttpClient(handler))
            {
                //var content = new StreamContent(new FileStream(inFilePath, FileMode.Open, FileAccess.Read, FileShare.Read, bufferSize: 4096, useAsync: true));
                using (var content = new StreamContent(new FileStream(inFilePath, FileMode.Open)))
                {
                    content.Headers.Remove("Content-Type");
                    content.Headers.Add("Content-Type", "application/octet-stream");
                    using (var req = new HttpRequestMessage(HttpMethod.Put, inUrl))
                    {
                        string authInfo = String.Format("{0}:{1}", Program.Config.MediaStorageList.Find(o => o.Name == "Viz Media Engine Test").UserName, Program.Config.MediaStorageList.Find(o => o.Name == "Viz Media Engine Test").Password);
                        authInfo = Convert.ToBase64String(Encoding.Default.GetBytes(authInfo));
                        req.Headers.Add("Authorization", "Basic " + authInfo);
                        req.Headers.Remove("Expect");
                        req.Headers.Add("Expect", "");
                        //req.Headers.TransferEncodingChunked = true;
                        req.Content = content;
                        // Ignore Certificate validation failures (aka untrusted certificate + certificate chains)
                        ServicePointManager.ServerCertificateValidationCallback = ((sender, certificate, chain, sslPolicyErrors) => true);
                        using (HttpResponseMessage resp = await client.SendAsync(req))
                        {
                            //This part is specific to the setup on an Expo we're at...
                            if (resp.StatusCode == HttpStatusCode.Redirect || resp.StatusCode == HttpStatusCode.TemporaryRedirect)
                            {
                                string redirectUrl = resp.Headers.Location.ToString();
                                if (redirectUrl.Contains("vme-store"))
                                {
                                    redirectUrl = redirectUrl.Replace("vme-store", "10.230.0.11");
                                }
                                return await HttpPut(redirectUrl, inFilePath);
                            }
                            resp.EnsureSuccessStatusCode();
                            return await resp.Content.ReadAsStringAsync();
                        }
                    }
                }
            }
        }
    }

我得到的例外是:

System.NotSupportedException was unhandled
HResult=-2146233067
Message=The stream does not support concurrent IO read or write operations.
Source=System
StackTrace:
     at System.Net.ConnectStream.InternalWrite(Boolean async, Byte[] buffer, Int32 offset, Int32 size, AsyncCallback callback, Object state)
   at System.Net.ConnectStream.BeginWrite(Byte[] buffer, Int32 offset, Int32 size, AsyncCallback callback, Object state)
   at System.Net.Http.StreamToStreamCopy.BufferReadCallback(IAsyncResult ar)
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at VizWolfInnerServer.Tools.HttpConnector.<HttpPut>d__39.MoveNext() in c:'Users'christer'Documents'Visual Studio 2012'Projects'VizWolfNew'VizWolfInnerServer'Tools'HttpConnector.cs:line 202
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at VizWolfInnerServer.Tools.VizAPIConnector.<VmeUploadMedia>d__0.MoveNext() in c:'Users'christer'Documents'Visual Studio 2012'Projects'VizWolfNew'VizWolfInnerServer'Tools'VizAPIConnector.cs:line 187
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.AsyncMethodBuilderCore.<ThrowAsync>b__1(Object state)
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()
   at System.Threading.ThreadPoolWorkQueue.Dispatch()
InnerException: 

我很难为HttpClient找到合适的文档和示例,我很难弄清楚为什么这突然不起作用(使用StringContent而不是StreamContent的完全类似的方法非常有效(。。。

它最初是从自己的线程调用的,然后是这样的:

public static async void VmeUploadMedia(string inUploadLink, string inFilePath)
{
    string result = await HttpConnector.HttpPut(inUploadLink, inFilePath);
}

有人发现任何明显的东西吗?

感谢

更新

事实证明,让博览会的人用它的IP映射他们的存储名称,这样我就可以回到我的原始代码,这是最好的解决方案。我遇到的问题与AllowAutoRedirect=false有关。HttpResponseMessage resp=await客户端上发生异常。SendAsync(req(,即使没有真正进行重定向。我有点不知道为什么会发生这种情况,但使用这段代码,现在一切都正常了:

public static async Task<string> HttpPut(string inUrl, string inFilePath)
    {
        using (var client = new HttpClient())
        {
            using (var content = new StreamContent(File.OpenRead(inFilePath)))
            {
                content.Headers.Remove("Content-Type");
                content.Headers.Add("Content-Type", "application/octet-stream");
                using (var req = new HttpRequestMessage(HttpMethod.Put, inUrl))
                {
                    string authInfo = String.Format("{0}:{1}", Program.Config.MediaStorageList.Find(o => o.Name == "Viz Media Engine Test").UserName, Program.Config.MediaStorageList.Find(o => o.Name == "Viz Media Engine Test").Password);
                    authInfo = Convert.ToBase64String(Encoding.Default.GetBytes(authInfo));
                    req.Headers.Add("Authorization", "Basic " + authInfo);
                    req.Headers.Remove("Expect");
                    req.Headers.Add("Expect", "");
                    req.Content = content;
                    // Ignore Certificate validation failures (aka untrusted certificate + certificate chains)
                    ServicePointManager.ServerCertificateValidationCallback = ((sender, certificate, chain, sslPolicyErrors) => true);
                    using (HttpResponseMessage resp = await client.SendAsync(req))
                    {
                        resp.EnsureSuccessStatusCode();
                        return await resp.Content.ReadAsStringAsync();
                    }
                }
            }
        }
    }

感谢那些试图帮助的人

C# HttpClient PUT

事实证明,让expo人员将他们的存储名称映射到它的IP,这样我就可以回到我的原始代码,这是最好的解决方案。我遇到的问题与AllowAutoRedirect=false有关。HttpResponseMessage resp=await客户端上发生异常。SendAsync(req(,即使没有真正进行重定向。我有点不知道为什么会发生这种情况,但使用这段代码,现在一切都正常了:

public static async Task<string> HttpPut(string inUrl, string inFilePath)
    {
        using (var client = new HttpClient())
        {
            using (var content = new StreamContent(File.OpenRead(inFilePath)))
            {
                content.Headers.Remove("Content-Type");
                content.Headers.Add("Content-Type", "application/octet-stream");
                using (var req = new HttpRequestMessage(HttpMethod.Put, inUrl))
                {
                    string authInfo = String.Format("{0}:{1}", Program.Config.MediaStorageList.Find(o => o.Name == "Viz Media Engine Test").UserName, Program.Config.MediaStorageList.Find(o => o.Name == "Viz Media Engine Test").Password);
                    authInfo = Convert.ToBase64String(Encoding.Default.GetBytes(authInfo));
                    req.Headers.Add("Authorization", "Basic " + authInfo);
                    req.Headers.Remove("Expect");
                    req.Headers.Add("Expect", "");
                    req.Content = content;
                    // Ignore Certificate validation failures (aka untrusted certificate + certificate chains)
                    ServicePointManager.ServerCertificateValidationCallback = ((sender, certificate, chain, sslPolicyErrors) => true);
                    using (HttpResponseMessage resp = await client.SendAsync(req))
                    {
                        resp.EnsureSuccessStatusCode();
                        return await resp.Content.ReadAsStringAsync();
                    }
                }
            }
        }
    }

感谢那些试图帮助的人

using (HttpResponseMessage resp = await client.SendAsync(req))

这一行似乎会为该执行创建一个新的上下文,因此会创建新的线程上下文,也许您不能这样做,因为您将共享FileStream的锁。

看起来您再次调用HttpPut(),但FileStream仍处于打开状态。在从FileStream内部递归调用HttpPut()之前,请尝试先处理它。

//This part is specific to the setup on an Expo we're at...
                            if (resp.StatusCode == HttpStatusCode.Redirect || resp.StatusCode == HttpStatusCode.TemporaryRedirect)
                            {
                                string redirectUrl = resp.Headers.Location.ToString();
                                if (redirectUrl.Contains("vme-store"))
                                {
                                    redirectUrl = redirectUrl.Replace("vme-store", "10.230.0.11");
                                }
                                content.Dispose();
                                return await HttpPut(redirectUrl, inFilePath);
                        }

此外,您可能希望处理任何其他IDisposable对象(如http响应(,以确保在深入堆栈跟踪之前释放所有资源。这是递归的一个问题,当您使用Using语句时,您不会离开它们的作用域,因此它们不会完成自己的工作。