Lal*_*ale 5 .net c# upload multithreading dotnet-httpclient
我正在开发一个项目,该项目有一些跑步者,每个跑步者都可以同时上传文件。任意地我会得到一个“流不支持并发 IO 读或写操作”错误。
我们已经看到它发生在小文件(5Mb~10Mb)和大文件(1Gb~2Gb)上。我们甚至尝试了完全相同的文件,有时我们能够重现它。
我们的设置具有 NTLM 身份验证、自签名证书并使用 OWIN/Katana 自托管。全部使用 .Net 编写。
它只发生在(到目前为止)在虚拟机上,我们还没有使用物理机来解决这个问题,尽管其中一些虚拟机真的很强大
这是我的代码:
客户
public Guid Upload(string filePath, Guid taskId)
{
if (string.IsNullOrEmpty(filePath)) { throw new ArgumentException("Value cannot be empty.", "filePath"); }
var key = Guid.Empty;
var fileInfo = new System.IO.FileInfo(filePath);
using (var fileStream = new System.IO.FileStream(filePath, System.IO.FileMode.Open))
{
var content = new StreamContent(fileStream);
content.Headers.Add("TaskId", taskId.ToString());
content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
content.Headers.ContentDisposition.FileName = fileInfo.Name;
content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
content.Headers.ContentLength = fileInfo.Length;
key = HttpClient.PostGet<Guid>(content, "https://localhost:1234/Files/Upload");
}
return key;
}
public T PostGet<T>(string url, HttpContent content, IDictionary<string, string> headers)
{
using (var client = httpClient) // <-- look below to check how we build this
{
client.AddHeaders(headers);
HttpResponseMessage response = null;
try
{
response = client.PostAsync(url, content).Result;
ensureSuccessStatusCode(response);
var jsonResult = response.Content.ReadAsStringAsync().Result;
var obj = Deserialize<T>(jsonResult);
return obj;
}
finally
{
if (response != null)
{
response.Dispose();
}
}
}
}
private System.Net.Http.HttpClient httpClient
{
get
{
System.Net.Http.HttpClient client = null;
if (authenticationEnabled)
{
if (credentials == null)
{
client = new System.Net.Http.HttpClient(new CertValidatingWebRequestHandler()
{
UseDefaultCredentials = true
});
}
else
{
client = new System.Net.Http.HttpClient(new CertValidatingWebRequestHandler()
{
Credentials = credentials
});
}
}
else
{
client = new System.Net.Http.HttpClient();
}
client.Timeout = TimeSpan.FromMilliseconds(TimeOutInMilliseconds);
return client;
}
}
public class CertValidatingWebRequestHandler : WebRequestHandler
{
public CertValidatingWebRequestHandler()
{
this.ServerCertificateValidationCallback = ValidateRemoteCert;
}
private bool ValidateRemoteCert(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslpolicyErrors)
{
return true;
}
}
Run Code Online (Sandbox Code Playgroud)
服务器
[HttpPost]
[Route("Upload")]
public async Task<IHttpActionResult> Upload()
{
return await upload(Guid.Empty);
}
private async Task<IHttpActionResult> upload(Guid appendToKey)
{
if (Request.Content.Headers.ContentType.MediaType.Equals("application/octet-stream", StringComparison.OrdinalIgnoreCase))
{
var taskId = Guid.Empty;
if (Request.Headers.Contains("TaskId"))
{
var taskIdValue = Request.Headers.GetValues("TaskId").FirstOrDefault();
taskId = new Guid(taskIdValue);
}
var fileName = Request.Content.Headers.ContentDisposition.FileName;
fileName = fileName.Trim(' ', '"');
if (string.IsNullOrEmpty(fileName))
{
throw new HttpResponseException(HttpStatusCode.BadRequest);
}
var key = Guid.NewGuid();
var directoryPath = string.Empty;
if (appendToKey == Guid.Empty)
{
directoryPath = createStorageDirectory(key);
}
else
{
var fileInfo = fileStorage.GetFileInfo(appendToKey);
if (fileInfo == null)
{
throw new Exception(string.Format("File with key {0} was not found.", appendToKey));
}
directoryPath = fileInfo.Path;
}
var filePath = fileSystem.Combine(directoryPath, fileName);
using (var httpStream = await Request.Content.ReadAsStreamAsync())
{
using (var fileStream = new FileStream(filePath, FileMode.CreateNew))
{
await httpStream.CopyToAsync(fileStream).ContinueWith(t =>
{
try
{
handleResponse(key, directoryPath, fileName, appendToKey, taskId, t);
}
catch (Exception e)
{
deleteStorageFolder(key);
logger.Log(LogType.Error, e);
throw;
}
});
}
}
return Ok(key);
}
else
{
throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
}
}
Run Code Online (Sandbox Code Playgroud)
完全错误
System.AggregateException: One or more errors occurred. ---> System.NotSupportedException: The stream does not support concurrent IO read or write operations.
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.TryStartWriteSync(Int32 bytesRead)
at System.Net.Http.StreamToStreamCopy.BufferReadCallback(IAsyncResult ar)
--- End of inner exception stack trace ---
---> (Inner Exception #0) System.NotSupportedException: The stream does not support concurrent IO read or write operations.
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.TryStartWriteSync(Int32 bytesRead)
at System.Net.Http.StreamToStreamCopy.BufferReadCallback(IAsyncResult ar)<---
Run Code Online (Sandbox Code Playgroud)
很抱歉这篇很长的帖子,但我认为信息越多对你越好。
我正在尝试禁用身份验证和证书以进一步隔离问题。稍后我会更新。
提前致谢。任何帮助/建议/想法都非常受欢迎!!!!
| 归档时间: |
|
| 查看次数: |
981 次 |
| 最近记录: |