我有一些奇怪的行为,我无法弄清楚。
我使用WCF服务将文件保存到某个数据库表。 WCF服务有一个方法,它将JSON字符串作为参数。在这种情况下,JSON是一个序列化命令,其中包含List<FileData>
和其他属性。 WCF服务反序列化JSON并为此特定命令运行CommandHandler
。
最终用户在尝试上传大小为52 MB的文件时遇到了错误。 WCF服务返回404错误。
我能够在Visual Studio中重现这一点。根据此article更改配置文件后,404消失了。
但现在出现了一个新的异常:当命令成功序列化客户端,由WCF成功处理后,反序列化抛出OutOfMemoryException
。这是堆栈跟踪的顶部:
at Newtonsoft.Json.JsonTextReader.ReadData(Boolean append,Int32 charsRequired) at Newtonsoft.Json.JsonTextReader.ReadData(Boolean append) at Newtonsoft.Json.JsonTextReader.ReadStringIntoBuffer(Char quote) at Newtonsoft.Json.JsonTextReader.ParseString(Char quote) at Newtonsoft.Json.JsonTextReader.ParseValue() at Newtonsoft.Json.JsonTextReader.ReadInternal() at Newtonsoft.Json.JsonReader.ReadAsBytesInternal() at Newtonsoft.Json.JsonTextReader.ReadAsBytes() at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.ReadForType(JsonReader reader,JsonContract contract,Boolean hasConverter)
我写了一个单元测试来证明这个bug。但是,在这个测试通过的情况下,换句话说,没有抛出OutOfMemoryException
。
为了完整性而进行的测试:
[TestMethod]
public void LoadBigFile_SerializeDeserialize_DoesntThrowOutOfMemoryException()
{
// Arrange
byte[] bytes = new byte[80000000];
Random r = new Random(23);
r.NextBytes(bytes);
var command = new SomeCommand(new List<FileData>
{
new FileData(
fileFullName: @"D:\SomePdfFile.pdf",
modifyDate: DateTime.MaxValue,
data: bytes
)
});
var data = JsonConvert.SerializeObject(command);
// Act
var deserializedCommand =
JsonConvert.DeserializeObject<SomeCommand>(data);
// Assert
Assert.AreEqual(bytes.Length, deserializedCommand.Files.First().Data.Length);
}
所以,我抓住了机会,改变了生产中的配置文件,并尝试上传相同的文件。这才有效!!!没有OutOfMemoryException
!
现在我的问题是,为什么OutOfMemoryException
只发生在Visual Studio中,而VS的同一个实例中的单元测试却没有?感觉有点奇怪,我无法在Visual Studio中测试上传大文件,而它在生产中工作。请注意,我也尝试在Release模式下运行Debug。
一些细节:
答案 0 :(得分:5)
我在单元测试中通过将byte[] bytes = new byte[80000000];
更改为byte[] bytes = new byte[52000000];
并在循环中运行(2次)来复制{{0,0},{0,1},{0,2},{0,3},{0,4},{0,5},{0,6},{0,63}}
。测试运行器是32位。
回到IIS Express - 我认为你使用的是32位版本。您可以在
更改此设置工具|选项|项目和解决方案|网站项目|使用64位版本的IIS Express