简体   繁体   English

C#HttpClient PUT

[英]C# HttpClient PUT

For some reason my below code that used to work now consequently raises an exception: 出于某种原因,我现在使用的下面的代码因此引发了一个异常:

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();
                        }
                    }
                }
            }
        }
    }

The exception I'm getting is: 我得到的例外是:

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: 

I'm having a very hard time finding proper documentation and examples for HttpClient, and I'm struggling with figuring out why this suddenly doesn't work (a totally similar method with StringContent instead of StreamContent works perfectly)... 我很难找到HttpClient的正确文档和示例,我正在努力弄清楚为什么这突然不起作用(与StringContent完全相似的方法而不是StreamContent完美地工作)...

It originally gets called from it's own thread, and then like this: 它最初是从它自己的线程调用的,然后像这样:

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

Anyone spot anything obvious? 有人发现什么明显吗?

Thanks 谢谢

UPDATE UPDATE

Turns out getting the expo-guys to map their storage-name with it's IP so I could go back to my original code was the best solution. 结果让那些世界各地的人用他们的IP映射他们的存储名称,所以我可以回到原来的代码是最好的解决方案。 The problem I was having is something to do with AllowAutoRedirect = false. 我遇到的问题与AllowAutoRedirect = false有关。 The exception occured on HttpResponseMessage resp = await client.SendAsync(req), even if there was no redirection really going on. 在HttpResponseMessage resp = await client.SendAsync(req)上发生异常,即使实际上没有重定向。 I'm kind of lost as to why it was even happening, but using this code everything is working now: 我有点迷失为什么它甚至发生了,但使用这个代码现在一切正常:

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();
                    }
                }
            }
        }
    }

Thanks to the people who were trying to help 感谢那些试图帮助的人们

Turns out getting the expo-guys to map their storage-name with it's IP so I could go back to my original code was the best solution. 结果让那些世界各地的人用他们的IP映射他们的存储名称,所以我可以回到原来的代码是最好的解决方案。 The problem I was having is something to do with AllowAutoRedirect = false. 我遇到的问题与AllowAutoRedirect = false有关。 The exception occured on HttpResponseMessage resp = await client.SendAsync(req), even if there was no redirection really going on. 在HttpResponseMessage resp = await client.SendAsync(req)上发生异常,即使实际上没有重定向。 I'm kind of lost as to why it was even happening, but using this code everything is working now: 我有点迷失为什么它甚至发生了,但使用这个代码现在一切正常:

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();
                    }
                }
            }
        }
    }

Thanks to the people who were trying to help 感谢那些试图帮助的人们

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

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

It looks like you are calling HttpPut() again, but you still have the FileStream opened. 看起来你再次调用HttpPut() ,但你仍然打开了FileStream Try disposing of the FileStream before you recursively call HttpPut() from within itself. 在从内部递归调用HttpPut()之前尝试处理FileStream。

//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);
                        }

In addition, you probably would want to dispose of any other IDisposable objects like the http response to ensure that all resources are freed before you proceed deeper into the stack trace. 此外,您可能希望处理任何其他IDisposable对象(如http响应),以确保在深入到堆栈跟踪之前释放所有资源。 This is one problem with recursion, that while you are using Using statements you not leaving their scope so they are not doing their job. 这是递归的一个问题,当你使用Using语句时,你不会离开它们的范围,所以它们没有完成它们的工作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM