请求不等待.net中的响应

时间:2014-08-21 10:20:04

标签: c# .net request response webrequest

我有一个Windows服务,它将文件上传到正在处理它们的其他网站。问题是,对于小文件,它工作正常,并且从那里获得响应,但是对于大文件(大约6分钟处理),它将永远处于等待模式。

以下是外部网站发布方法代码的一部分:

try
{
  ...
  LogResults();
  return string.Empty;
}
catch (Exception e)
{
  return e.Message;
}

问题是我甚至可以看到大型文件的日志,所以这意味着网站总是返回值,但对于大型文件,我的Windows服务并不等待它们。

这是来自Windows服务的代码

var valuesp = new NameValueCollection
{
     { "AccountId", datafeed.AccountId }
};

byte[] resultp = UploadHelper.UploadFiles(url, uploadFiles, valuesp);
response = Encoding.Default.GetString(resultp);

UploadFiles方法返回小文件的值,但永远等待大文件。

以下是UploadFiles的完整代码

public static byte[] UploadFiles(string address, IEnumerable<UploadFile> files, NameValueCollection values)
{
    var request = WebRequest.Create(address);
    request.Timeout = System.Threading.Timeout.Infinite; //3600000; // 60 minutes
    request.Method = "POST";
    var boundary = "---------------------------" +
                   DateTime.Now.Ticks.ToString("x", NumberFormatInfo.InvariantInfo);
    request.ContentType = "multipart/form-data; boundary=" + boundary;
    boundary = "--" + boundary;

    using (var requestStream = request.GetRequestStream())
    {
        // Write the values
        if (values != null)
        {
            foreach (string name in values.Keys)
            {
                var buffer = Encoding.ASCII.GetBytes(boundary + Environment.NewLine);
                requestStream.Write(buffer, 0, buffer.Length);
                buffer =
                    Encoding.ASCII.GetBytes(string.Format("Content-Disposition: form-data; name=\"{0}\"{1}{1}", name,
                                                          Environment.NewLine));
                requestStream.Write(buffer, 0, buffer.Length);
                buffer = Encoding.UTF8.GetBytes(values[name] + Environment.NewLine);
                requestStream.Write(buffer, 0, buffer.Length);
            }
        }

        // Write the files
        if (files != null)
        {
            foreach (var file in files)
            {
                var buffer = Encoding.ASCII.GetBytes(boundary + Environment.NewLine);
                requestStream.Write(buffer, 0, buffer.Length);
                buffer =
                    Encoding.UTF8.GetBytes(
                        string.Format("Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"{2}", file.Name,
                                      file.Filename, Environment.NewLine));
                requestStream.Write(buffer, 0, buffer.Length);
                buffer =
                    Encoding.ASCII.GetBytes(string.Format("Content-Type: {0}{1}{1}", file.ContentType,
                                                          Environment.NewLine));
                requestStream.Write(buffer, 0, buffer.Length);
                requestStream.Write(file.Stream, 0, file.Stream.Length);
                buffer = Encoding.ASCII.GetBytes(Environment.NewLine);
                requestStream.Write(buffer, 0, buffer.Length);
            }
        }

        var boundaryBuffer = Encoding.ASCII.GetBytes(boundary + "--");
        requestStream.Write(boundaryBuffer, 0, boundaryBuffer.Length);
    }

    using (var response = request.GetResponse())
    using (var responseStream = response.GetResponseStream())
    using (var stream = new MemoryStream())
    {
        responseStream.CopyTo(stream);
        return stream.ToArray();
    }
}

我在这里做错了什么?

编辑:在本地,它甚至可以处理7-8分钟。但在现场环境中并没有。它可以与主应用程序IIS设置相关吗?它可以与Windows服务器设置相关吗?

编辑2:远程服务器web.config httpRuntime设置

<httpRuntime enableVersionHeader="false" maxRequestLength="300000" executionTimeout="12000" targetFramework="4.5" />

7 个答案:

答案 0 :(得分:6)

问题出在Azure Load Balancer上,默认情况下将Idle Timeout设置为4分钟。 Windows Azure博客的新帖子称,此超时现在可配置为4-30分钟之间的值

http://azure.microsoft.com/blog/2014/08/14/new-configurable-idle-timeout-for-azure-load-balancer/

然而,通过TCP发送额外的KeepAlive字节解决了这个问题,这告诉Load Balancer不会杀死请求。

HttpWebRequest request = (HttpWebRequest)WebRequest.Create(address);
...
request.Proxy = null;
request.ServicePoint.SetTcpKeepAlive(true, 30000, 5000); //after 30 seconds, each 5 second

将Proxy设置为null(不使用代理)是强制操作,因为否则代理不会将tcp字节传递给服务器。

答案 1 :(得分:2)

使用符合RFC1867的方法上传文件

See this

然后:

 UploadFile[] files = new UploadFile[]
{
new UploadFile(fileName1),
new UploadFile(fileName2)
};

NameValueCollection form = new NameValueCollection();

form["name1"] = "value1";
form["name2"] = "xyzzy";

string response = UploadHelper.Upload(url, files, form);

这就是所有人!

编辑:

我使用上面的方法上传大小超过100MB的文件,我根本不使用ASP,它的工作非常完美!

答案 2 :(得分:2)

我有一个类似的问题,上传可以在本地工作,但在服务器上超时。这里有两件事情 - 我假设您正在谈论IIS7 +。如果没有,请告诉我,我很乐意删除我的答案。

首先,有ASP.NET查看此设置(在system.web下):

<!-- maxRequestLength is in KB - 10 MB here. This is needed by ASP.NET. Must match with maxAllowedContentLength under system.webserver/security/requestLimits -->
<httpRuntime targetFramework="4.5" maxRequestLength="1048576" />

然后是IIS:

<system.webServer>
    <security>
        <requestFiltering>
            <!-- maxAllowedContentLength in bytes - 10MB -->
            <requestLimits maxAllowedContentLength="10485760" />
        </requestFiltering>
    </security>
<system.webServer>

您需要同时显示这两个设置以及匹配工作的限制。请注意,一个是KB,另一个是字节。

答案 3 :(得分:1)

可能是由IIS上传限制引起的? 在IIS7中,标准值为30MB。见MSDN

EDIT1: 请注意,如果您在1个请求中上传多个文件,则会增加大小。

EDIT2: 在所有MS示例中,始终只有一个 Stream.Write()。 在MSDN中声明:在返回Stream对象之后,您可以使用Stream.Write方法使用HttpWebRequest发送数据。我对这句话的解释是你应该调用只写一次()。将要发送的所有数据放入缓冲区,然后调用Write()。

答案 4 :(得分:1)

您是否检查过远程服务器上的IIS文件大小限制?默认为30MB,因此如果您尝试上传的文件大于该文件,则会失败。以下是如何更改上传限制(IIS7):http://www.web-site-scripts.com/knowledge-base/article/AA-00696/0/Increasing-maximum-allowed-size-for-uploads-on-IIS7.html

答案 5 :(得分:1)

您可以使用AsyncCallback技术完成此任务。

什么是AsyncCallback?

当异步方法完成处理时,会自动调用AsyncCallback方法,其中可以执行后处理stmts。使用此技术,无需轮询或等待异步线程完成。

您可以从此链接中找到更多详细信息

AsynCallback

答案 6 :(得分:1)

您应该将此executionTimeout="12000"更改为executionTimeout="360000",这意味着将执行超时从2分钟更改为6分钟。