I'm calling 2 webservices from a .Net 3.5 Framework Client (Server is a more modern .NET Framework Server: 4.6).
Separated I run into no Problems, but if I call the methods in the order shown below I get the Problem that the VerifyFile method on the Server is never entered, and I instead immediately get a The server has committed a protocol Violation Section=ResponseStatusLine error on the Client. To be more exact: The Server Registers in the Events the VerifyFile request but doesn't enter the actual code until up to 6 minutes later (and immediately Returns something instead that causes the above error).
After much testing I could reduce it to the first method "DownloadFile" being the cause of the Problem. And that always when I return anything else than the statuscode ok from it (Content or not Content doesn't matter).
I'm at a complete loss with this phenomenon (I would have expected the Client to have Troubles, but the Server not entering that one code part until MINUTES later Looks like the Server is getting into Troubles itself, which is unexpected, also unexpected is that the SECOND method and not the original one is running into Problems there).
So my question is why is returning anything but HttpStatusCode.OK causing These Problems and what can I do to correct this?
Client:
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 I replaced the DownloadFile with: webClient.DownloadString("localhost/Download/DownloadFile");
Originally I also had only one new WebClient, but added the second one after the first failures.
Server:
[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
}
}
You can try three things.
Follow the http spec so you don't get this error
Add this to your client web.config
<system.net>
<settings>
<httpWebRequest useUnsafeHeaderParsing="true" />
</settings>
</system.net>
Set connnection header to close instead of keep alive
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;
}
}
My theory is that When you Get an error response from the server then the file isn't created. Suppose you are catching the DownloadFile exception that you should receive when you return any other response than OK.
GetFileLength probably returns an invalid number and according to this answer it can result in the error you have mentioned. As to why it takes 6 minutes to reach that server code - I guess it does some inner error handling before calling the method, and returning an error. Sadly ASP.net 4.* isn't open source so I am not really familiar with the inner workings.
I think it's a problem with a Keep-Alive
header. You can capture the http request and check this value. A value of true will try to mantain a connection opened. Not all proxies are compatible with this header.
Try to use two diferent WebClient
instances and dispose them before use the next one. Or force the header to false.
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();
Or wrap them in a using
statement:
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");
}
Check this post: WebClient is opening a new connection each time I download a file and all of them stay established
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With