在HttpResponseMessage中返回任何内容,但会导致服务器端Web服务调用延迟

时间:2018-06-08 09:01:35

标签: c# asp.net

我从.Net 3.5 Framework Client调用2个webservices(Server是一个更现代的.NET Framework Server:4.6)。

分离我遇到没有问题,但是如果我按照下面显示的顺序调用方法,我会遇到问题,即服务器上的VerifyFile方法永远不会输入,而是我立即得到 服务器已在客户端上提交协议Violation Section = ResponseStatusLine 错误。 更确切地说:服务器在事件中注册VerifyFile请求但直到最多6分钟后才输入实际代码(并立即返回导致上述错误的内容)。

经过大量测试后,我可以将其减少为第一种方法“DownloadFile”是问题的原因。总是当我从状态代码中返回任何其他内容时(内容与否无关紧要)。

我完全失去了这种现象(我本来希望客户有麻烦,但服务器没有输入那个代码部分,直到MINUTES后来看起来服务器正在进入麻烦本身,是出乎意料的,也是出乎意料的是SECOND方法而不是原来的方法遇到了问题。

所以我的问题是为什么除了HttpStatusCode.OK之外还返回任何导致这些问题的内容,我该怎么做才能纠正这个问题?

客户端:

WebClient webClient = new WebClient();
webClient.QueryString.Add("downloadId", id);
webClient.DownloadFile("localhost/Download/DownloadFile", @"c:\temp\local.txt");
webClient = new WebClient();
webClient.QueryString.Add("downloadId", id);
webClient.QueryString.Add("fileLength", GetFileLength(@"c:\temp\local.txt"));
var i = webClient.DownloadString("localhost/Download/VerifyFile");

Testwise我将DownloadFile替换为:webClient.DownloadString("localhost/Download/DownloadFile");

最初我也只有一个新的WebClient,但在第一次失败后添加了第二个。

服务器

[RoutePrefix("Download")]
public class DownloadController : ApiController
{
    [HttpGet]
    [Route("DownloadFile")]
    public IHttpActionResult DownloadFile(int downloadId){
        return ResponseMessage(GetFile(downloadId));
    }

    private HttpResponseMessage GetFile(int downloadId){
        HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);

        string filePath = GetFilePathFromDB(downloadid);

        if (filePath != String.Empty){
            var stream = new FileStream(filePath, FileMode.Open, FileAccess.ReadWrite);
            result.Content = new StreamContent(stream);
            result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
            result.Content.Headers.ContentDisposition.FileName = Path.GetFileName(filePath);
            result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
            result.Content.Headers.ContentLength = stream.Length;   
        }
        else{
            result = new HttpResponseMessage(HttpStatusCode.InternalServerError);
        }       
        return result;
    }

    [HttpGet]
    [Route("VerifyFile")]
    public IHttpActionResult VerifyFile(int downloadId, int fileLength)
    {
        return Content(HttpStatusCode.OK, "OK");
    }


    private string GetFilePathFromDB(int downloadId)
    {
         return @"C:\temp\mytest.txt"; // testcode
    }
}

3 个答案:

答案 0 :(得分:1)

你可以尝试三件事。

  1. 按照http规范进行操作,以免出现此错误

  2. 将此添加到您的客户端web.config

    <system.net>
       <settings>
         <httpWebRequest useUnsafeHeaderParsing="true" />
       </settings>
    </system.net>
    
  3. 将连接标头设置为关闭而不是保持活动

    class ConnectionCloseClient : WebClient
    {
        protected override WebRequest GetWebRequest(Uri address)
        {
            WebRequest request = base.GetWebRequest(address);
            if (request is HttpWebRequest)
            {
                (request as HttpWebRequest).KeepAlive = false;
            }
            return request;
        }
    }
    

答案 1 :(得分:1)

我的理论是,当您从服务器获得错误响应时,文件不会被创建。假设您正在捕获在返回除OK之外的任何其他响应时应该收到的DownloadFile异常。

GetFileLength可能返回一个无效的数字,根据此answer,它可能会导致您提到的错误。至于为什么需要6分钟才能到达服务器代码 - 我猜它在调用方法之前会做一些内部错误处理,并返回错误。可悲的是ASP.net 4. *不是开源的,所以我对内部工作并不熟悉。

答案 2 :(得分:1)

我认为这是Keep-Alive标题的问题。您可以捕获http请求并检查此值。值为true将尝试保持打开的连接。并非所有代理都与此标头兼容。

尝试使用两个不同的WebClient实例并在使用下一个实例之前将其处理掉。或强制标题为假。

WebClient webClient = new WebClient();
webClient.QueryString.Add("downloadId", id);
webClient.DownloadFile("localhost/Download/DownloadFile", @"c:\temp\local.txt");
webClient.Dispose();

webClient2 = new WebClient();
webClient2.QueryString.Add("downloadId", id);
webClient2.QueryString.Add("fileLength", GetFileLength(@"c:\temp\local.txt"));
var i = webClient2.DownloadString("localhost/Download/VerifyFile");
webClient2.Dispose();

或者将它们包装在using声明中:

using (WebClient webClient = new WebClient())
{
    webClient.QueryString.Add("downloadId", id);
    webClient.DownloadFile("localhost/Download/DownloadFile", @"c:\temp\local.txt");
}

using (WebClient webClient = new WebClient())
{
    webClient2 = new WebClient();
    webClient2.QueryString.Add("downloadId", id);
    webClient2.QueryString.Add("fileLength", GetFileLength(@"c:\temp\local.txt"));
    var i = webClient2.DownloadString("localhost/Download/VerifyFile");
}

查看此帖子: WebClient is opening a new connection each time I download a file and all of them stay established