我已經實現了MultipartStreamProvider的自定義子類,以便將上傳的文件數據寫入自定義流。在寫入流之後,HttpContext有時會丟失。下面的代碼是一個簡化的repro來展示問題。如果自定義流實際上沒有在WriteAsync中執行任何異步工作(即,如果它保持在同一個線程中),那麼一切都按照您的預期工作。但是,只要我們將一些實際的異步工作引入到WriteAsync中(由Task.Delay在此模擬),那麼HttpContext就會(通常)丟失。我做錯了什麼,或者這是Web API框架中的錯誤?異步工作後MultipartStreamProvider失去HttpContext
public class TestApiController : ApiController
{
public class CustomMultipartStreamProvider : MultipartStreamProvider
{
private readonly List<string> _fileNames = new List<string>();
private readonly List<Stream> _fileStreams = new List<Stream>();
public CustomMultipartStreamProvider()
{
}
public override Stream GetStream(HttpContent parent, HttpContentHeaders headers)
{
string filename;
if (IsFileContent(headers, out filename))
{
var stream = new CustomStream();
_fileStreams.Add(stream);
_fileNames.Add(filename);
return stream;
}
return new MemoryStream();
}
private static bool IsFileContent(HttpContentHeaders headers, out string filename)
{
var contentDisposition = headers.ContentDisposition;
if (contentDisposition == null)
{
filename = null;
return false;
}
filename = UnquoteToken(contentDisposition.FileName);
return !string.IsNullOrEmpty(filename);
}
private static string UnquoteToken(string token)
{
if (string.IsNullOrWhiteSpace(token))
return token;
if (token.StartsWith("\"", StringComparison.Ordinal) && token.EndsWith("\"", StringComparison.Ordinal) && token.Length > 1)
return token.Substring(1, token.Length - 2);
return token;
}
}
class CustomStream : MemoryStream
{
public override async Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
await Task.Delay(100, cancellationToken); // simulate async work (if this line is commented out, everything works correctly)
await base.WriteAsync(buffer, offset, count, cancellationToken);
}
}
[Route("api/test/multipart")]
public async Task<string> PutMultiPart()
{
// Check if the request contains multipart/mixed content
if (!Request.Content.IsMimeMultipartContent("mixed"))
throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
// Read the multipart data
var multipartStreamProvider = new CustomMultipartStreamProvider();
await Request.Content.ReadAsMultipartAsync(multipartStreamProvider);
if (HttpContext.Current != null)
{
return "good";
}
else
{
return "bad";
}
}
}
出於測試目的,我發送請求基本上是這樣的:
Content-Type: multipart/mixed; boundary=boundary42
--boundary42
Content-Type: application/json
{
Description: "test file"
}
--boundary42
Content-Type: application/octet-stream
Content-Disposition: inline; filename=hello.txt
Hello world.
--boundary42--
你有(https://blogs.msdn.microsoft ['targetFramework'在'web.config'設置爲'4.5'或更高版本] .COM/Webdev的/ 2012/11/19 /全約-的httpRuntime-targetframework /)? –
@StephenCleary感謝您的提示 - 事實證明它已設置爲4.0。但是,更改爲4.5似乎沒有幫助... – jr76
@ jr75:您是否確實在ASP.NET 4.5或更新的版本上運行?你是否安裝了'Microsoft.Bcl.Async' NuGet軟件包? –