将数据发布到Azure中托管的Web API服务时,我遇到了一个奇怪的问题,并且非常感谢。
我编写了一个非常基本的Web API服务,它有一个控制器,通过Post方法接收List。我使用从HttpClientFactory
创建的客户端通过控制台应用程序将数据发布到此API。
当我在本地调试时,一切正常,我成功发布了一个包含100个元素的List,并将其写入我的本地数据库。如果我将本地Web API代码切换为指向我的Azure数据库,它仍然可以正常工作,我可以毫无问题地收到100个元素并写入Azure数据库实例。
当我将API服务部署到我的Azure帐户并挂钩我的控制台应用程序以向其发布数据时 - 它与包含最多45个元素的List完美配合,并且PostAsync等待大约6分钟然后失败内部服务器错误。
所以我的问题是为什么服务能够在大约一秒钟内发布43个元素到44个元素失败,但需要花费6分钟才能完成?
我应该指出我的List包含100个重复的项目,因为我正在生成用于测试的数据,因此集合中的特定元素没有任何错误(或不同)。
T是一个简单的类,有大约30个属性,没有子元素,所以我没有发布一个庞大的结构。
我的想法是,这必须是一个大小限制,在我的本地计算机上没有生效,但是当我部署到Azure时。我绝不是Web API专家,所以我不知道从哪里开始寻找。
一些客户端代码(当i <= 43时完美运行):
List<Foo> results = new List<Foo>();
for (int i = 1; i < 100; i++)
{
results.Add(new Foo() { // Populated with data - removed for brevity });
}
StringContent content = new StringContent(JsonConvert.SerializeObject(results), Encoding.UTF8, "application/json");
HttpResponseMessage postDataResponse = await postClient.PostAsync(myWebApiServiceURL, content);
控制器方法:
[HttpPost]
public List<Foo>Post([FromBody]List<Foo> value)
{
return value;
}
我试过的Web.config设置没有效果:
<httpRuntime targetFramework="4.6.1" maxRequestLength="200000000" requestLengthDiskThreshold="16384" />
和
<add key="aspnet:MaxJsonDeserializerMembers" value="20000000"/>
我刚刚进行了一次测试,它不能处理44个元素内容长度= 53278
它的最大长度是当我的总元素是43内容长度= 48361时。
注意:我刚刚运行了一些测试,如果我减少了一些字符串属性中的数据长度(从而减少了每个元素的占用空间),我可以发布更多元素。因此,它必须是某个地方的消息大小限制!!
更新 - HMAC身份验证
确定原因始终是您在问题中未记录的最不期望的事情。我在我的API上启用了HMAC身份验证,当我从控制器中删除属性时,我可以发布10000个元素而不会出现问题。一旦我启用它,我就会被限制回到43。
在客户端上,我正在生成请求内容的MD5哈希作为标头签名的一部分,此过程在Web API服务的HMAC属性中重复。如果我从我的客户端和服务中删除这部分签名,那么我可以发布尽可能多的数据。我在客户端上注释掉的代码如下所示:
//Checking if the request contains body, usually will be null with HTTP GET and DELETE
if (request.Content != null)
{
byte[] content = await request.Content.ReadAsByteArrayAsync();
MD5 md5 = MD5.Create();
//Hashing the request body, any change in request body will result in different hash, we'll incure message integrity
byte[] requestContentHash = md5.ComputeHash(content);
requestContentBase64String = Convert.ToBase64String(requestContentHash);
}
我在服务中注释的代码如下:
byte[] hash = await ComputeHash(req.Content);
if (hash != null)
{
requestContentBase64String = Convert.ToBase64String(hash);
}
ComputeHash
功能:
private static async Task<byte[]> ComputeHash(HttpContent httpContent)
{
using (MD5 md5 = MD5.Create())
{
byte[] hash = null;
var content = await httpContent.ReadAsByteArrayAsync();
if (content.Length != 0)
{
hash = md5.ComputeHash(content);
}
return hash;
}
}
因此,上面的代码注释掉requestContentBase64String
在客户端和服务器上始终是一个空字符串,因此内容的MD5哈希不会被用作身份验证签名的一部分。
我现在必须研究这种行为的根本原因。
答案 0 :(得分:0)
https://blogs.msdn.microsoft.com/azureossds/2016/06/15/uploading-large-files-to-azure-web-apps/
检查Azure的最大帖子大小。取决于您的配置可能是问题。更改配置或查看将邮件大小减小为更小的块。