我已经实现了MultipartStreamProvider的自定义子类,以便将上传的文件数据写入自定义流。写入流后,HttpContext有时会丢失。下面的代码是一个简化的repro,演示了这个问题。如果自定义流实际上没有在WriteAsync中执行任何异步工作(即,如果它停留在同一个线程上),那么一切都按照您的预期进行。但是,只要我们将一些实际的异步工作引入WriteAsync(由Task.Delay模拟),就会(通常)丢失HttpContext。我做错了什么,或者这是Web API框架中的错误?
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--
答案 0 :(得分:3)
事实证明@ StephenCleary的建议是正确的:将web.config中的targetFramework设置为&gt; = 4.5解决了问题,但是,您必须设置正确 targetFramework属性。我首先尝试更改行
<compilation debug="true" targetFramework="4.0" />
到
<compilation debug="true" targetFramework="4.5" />
这没有效果。这是需要更新的httpRuntime元素:
<httpRuntime targetFramework="4.5" />