我从.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
}
}
答案 0 :(得分:1)
你可以尝试三件事。
按照http规范进行操作,以免出现此错误
将此添加到您的客户端web.config
<system.net>
<settings>
<httpWebRequest useUnsafeHeaderParsing="true" />
</settings>
</system.net>
将连接标头设置为关闭而不是保持活动
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