FTP Upload from WinService fails - c#

I have made a small test application(WinForms C#) to test FTP upload. This works perfectly.
I try to use the exact same method in a Windows Service I'm currently working on, but there I get '(426) Connection closed; transfer aborted.'-message.
I have made sure several times that the parameters to the method are exactly the same. They are! Next thought was the account my service is running under, but I've tried all possibilities, even running the service as 'User', supplying my own credentials. Then it should act like the WinForms app, right? No, it doesn't!
It's running fine until the line using (var requestStream = request.GetRequestStream()) which is the point of failure.
The FTP-server in question only allows active connections, so request.UsePassive is set to false.
Anyone got a clue?
public void UploadToFtp(string url, string filePath, string username, string password, bool mode)
{
var fileName = Path.GetFileName(filePath);
var request = (FtpWebRequest)WebRequest.Create(url + fileName);
request.Method = WebRequestMethods.Ftp.UploadFile;
request.Credentials = new NetworkCredential(username, password);
request.UsePassive = !mode;
request.UseBinary = true;
request.KeepAlive = false;
using (var fileStream = File.OpenRead(filePath))
{
using (var requestStream = request.GetRequestStream())
{
fileStream.CopyTo(requestStream);
requestStream.Close();
}
}
var response = (FtpWebResponse)request.GetResponse();
response.Close();
}
Adding trace logs of both scenarios:
Using a Windows application:
WebRequest::Create(ftp://someurl/somefile.txt)
FtpWebRequest#63289421::.ctor(ftp://someurl/somefile.txt)
Exiting WebRequest::Create() -> FtpWebRequest#63289421
Current OS installation type is 'Client'.
RAS supported: True
ServicePoint#14173886::ServicePoint(someurl:21)
FtpWebRequest#63289421::GetRequestStream()
FtpWebRequest#63289421::GetRequestStream(Method=STOR.)
FtpControlStream#22525719 - Created connection from 10.10.10.103:1865 to nnn.nnn.nnn.nnn:21.
Associating FtpWebRequest#63289421 with FtpControlStream#22525719
FtpControlStream#22525719 - Received response [xxxx
someurl>PROD server
Port21>Use active mode>
xxxx]
Sending command [USER myusername]
Received response [331 Enter password]
Sending command [PASS ********]
Received response [230-User logged in
Hi,I'am datagear PROD.
230 User logged in]
Sending command [OPTS utf8 on]
Received response [200 Command OPTS succeed]
Sending command [PWD]
Received response [257 "/CitData" is current directory]
Sending command [TYPE I]
Received response [200 Transfer mode set to BINARY]
Sending command [PORT 10,10,10,103,7,74]
Received response [200 Command PORT succeed]
Sending command [STOR somefile.txt]
Received response [150 Uploading in BINARY file somefile.txt]
Exiting FtpWebRequest#63289421::GetRequestStream()
Received response [226 Transfer completed]
Sending command [QUIT]
Received response [221-bye
Bye-Bye,see you again.
Using a Windows Service:
WebRequest::Create(ftp://someurl/somefile.txt)
FtpWebRequest#63289421::.ctor(ftp://someurl/somefile.txt)
Exiting WebRequest::Create() -> FtpWebRequest#25425822
Current OS installation type is 'Client'.
ServicePoint#31665793::ServicePoint(someurl:21)
FtpWebRequest#25425822::GetRequestStream()
FtpWebRequest#25425822::GetRequestStream(Method=STOR.)
FtpControlStream#51484875 - Created connection from 10.10.10.103:1759 to nnn.nnn.nnn.nnn:21.
Associating FtpWebRequest#25425822 with FtpControlStream#51484875
FtpControlStream#51484875 - Received response [xxxx
someurl>PROD server
Port21>Use active mode>
xxxx]
Sending command [USER myusername]
Received response [331 Enter password]
Sending command [PASS ********]
Received response [230-User logged in
Hi,I'am datagear PROD.
230 User logged in]
Sending command [OPTS utf8 on]
Received response [200 Command OPTS succeed]
Sending command [PWD]
Received response [257 "/CitData" is current directory]
Sending command [TYPE I]
Received response [200 Transfer mode set to BINARY]
Sending command [PORT 10,10,10,103,6,224]
Received response [200 Command PORT succeed]
Sending command [STOR somefile.txt]
Received response [426 Transfer failed]
(Releasing FTP connection#51484875.)
GetRequestStream - The remote server returned an error: (426) Connection closed; transfer aborted..
at System.Net.FtpWebRequest.SyncRequestCallback(Object obj)
at System.Net.CommandStream.Dispose(Boolean disposing)
at System.IO.Stream.Close()
at System.Net.ConnectionPool.Destroy(PooledStream pooledStream)
at System.Net.ConnectionPool.PutConnection(PooledStream pooledStream, Object owningObject, Int32 creationTimeout, Boolean canReuse)
at System.Net.FtpWebRequest.FinishRequestStage(RequestStage stage)
at System.Net.FtpWebRequest.GetRequestStream()
Exiting FtpWebRequest#25425822::GetRequestStream()
The one that works has a line saying 'RAS Supported'. Maybe interesting, don't know.

The Windows Firewall caused the problem. When running from a WinService I had to open the firewall for this service. When running from VS environment it seems that the firewall is already open for VS (although the list of pass-through applications in WinFirewall don't show it) and therefore all seems to run well.

Related

Error 500 Trying to Connect to NetSuite RESTlet using C#

I'm trying to build a connector between a credit card processor and a client's NetSuite account to help automate their reconciliation process. Not having any trouble pulling info from their card processor, except occasionally when it has its own error 500. Still trying to find a way to better handle it than what I'm doing.
Anyway, the problem is occurring when I try to connect to the RESTlet in their NetSuite account. I can't seem to get it to properly connect, and all I get are error 500 responses. The problem doesn't seem to be the RESTlet as I can communicate with it fine when using tools like "Send HTTP Tool" to test it out. This is the code I'm using currently:
JavaScriptSerializer jss = new JavaScriptSerializer();
String content = jss.Serialize(rd);
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(this.nsURL);
req.ContentType = "application/json";
req.ContentLength = content.Length;
req.Method = "POST";
WebHeaderCollection headers = new WebHeaderCollection();
headers.Add("User-Agent-X", "SuiteScript-Call");
headers.Add("Authorization", String.Format("NLAuth nlauth_account={0},nlauth_email={1},nlauth_signature={2},nlauth_role={3}",
this.nsAccount, this.nsEmail, this.nsPassword, this.nsRole));
req.Headers = headers;
using (StreamWriter requestWriter = new StreamWriter(req.GetRequestStream()))
{
requestWriter.Write(content);
}
HttpWebResponse resp = (HttpWebResponse)req.GetResponse(); // error occurs here
Stream stream = resp.GetResponseStream();
using (StreamReader reader = new StreamReader(stream))
{
String response = reader.ReadToEnd();
Console.WriteLine(response);
}
And this is the error recorded:
[System.Net.WebException] The remote server returned an error: (500) Internal Server Error.
The error occurs at the point I try to retrieve the response from the HttpWebRequest object. I have tried sending the data instead as a byte array, but that causes a different error at the point I actually write the data to the connection. The RESTlet is also setup to log the data it receives upon being called, but this error is occurring before the RESTlet function can even be triggered.
I've spent too much time trying various different "fixes" to get this to work with no luck.
---- EDIT ----
Forgot to mention that I'm using Visual Studio 2010 Pro and targeting .NET 4.

Why is my Windows CE device unable to successfully invoke my server's REST methods?

This is related/sort of a followup to this question but contains more and more specific information.
I have a REST app running on my PC. I need to call some of the methods on the server from a handheld WindowsCE device that uses the compact framework.
I can contact the server's methods from Postman, so it's not a problem that way. In Postman, I use:
http://localhost:21609/api/inventory/sendXML/duckbill/platypus/bloo
...and with this I reach the breakpoint in this REST method on my server app:
[HttpPost]
[Route("api/inventory/sendxml/{userId}/{pwd}/{filename}")]
public async Task SendInventoryXML(String userId, String pwd, String fileName)
However, although using "PPP_PEER" is the way to contact the PC from the handheld device (127.0.0.1 doesn't fly, because the handheld sees that as being itself, and commits egregious acts of cannibalism when trying to contact that address) - as can be seen by this TCP code that does work from the handheld device:
string pingString = "PING|";
TcpClient client = new TcpClient("PPP_PEER", 7727);
try
{
try
{
Stream s = client.GetStream();
StreamReader sr = new StreamReader(s);
StreamWriter sw = new StreamWriter(s) { AutoFlush = true };
String response = String.Empty;
if (firstRecord)
{
sw.WriteLine(pingString);
. . .
...trying to use PPP_PEER to call the REST method fails.
Here is the code I use to try to do that:
//HHSConsts
public static string BASE_REST_URL = "http://PPP_PEER:21609/api/";
. . .
//frmMain
private void SendInventories()
{
try
{
foreach (String tblname in listBoxWork.Items)
{
String xmlData = hhsdbutils.GetINVDataAsXMLFromTable(tblname, fileName);
String uri = String.Format("{0}inventory/sendXML/duckbill/platypus/{1}",
HHSConsts.BASE_REST_URL, fileName);
fileXferImp = HHSConsts.GetFileTransferMethodology();
fileXferImp.SendDataContentsAsXML(uri, xmlData, tblname);
. . .
// FileXferREST.cs
public void SendDataContentsAsXML(String destinationPath, String data, String fileName,
String siteNumber, bool firstRecord, bool lastRecord)
{
SendHTTPRequestNoCredentials(destinationPath, HttpMethods.POST, data, "application/xml");
}
public static HttpWebRequest SendHTTPRequestNoCredentials(string uri, HttpMethods method,
string data, string contentType)
{
WebRequest request = WebRequest.Create(uri);
try
{
request.Method = Enum.ToObject(typeof(HttpMethods), method).ToString();
request.ContentType = contentType;
((HttpWebRequest)request).Accept = contentType;
((HttpWebRequest)request).KeepAlive = false;
((HttpWebRequest)request).ProtocolVersion = HttpVersion.Version10;
if (method != HttpMethods.GET && method != HttpMethods.DELETE)
{
byte[] arrData = Encoding.UTF8.GetBytes(data);
request.ContentLength = arrData.Length;
using (Stream oS = request.GetRequestStream())
{
oS.Write(arrData, 0, arrData.Length);
}
}
else
{
request.ContentLength = 0;
}
}
catch (WebException webex)
{
HttpWebResponse hwr = (HttpWebResponse)webex.Response;
HttpStatusCode hsc = hwr.StatusCode;
String webExMsgAndStatusCode = String.Format("{0} Status code == {1}", webex.Message,
hsc.ToString());
ExceptionLoggingService.Instance.WriteLog(String.Format("From
FileXferREST.SendHTTPRequestNoCredentials: {0}", webExMsgAndStatusCode));
}
return request as HttpWebRequest;
}
No exception is thrown; it simply doens't work.
When attempting this call, I run rawcap to capture the packages being sent over the network with these command line args:
rawcap 127.0.0.1 [fileName].pcap
I then open the .pcap file in Wireshark, search for "21609" and get this TCP stream:
...I added the screen shot above to show the red/blue coloration for the request/response, but here is the entire rawcap/Wireshark conversation involving port 21609:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
POST /api//inventory/sendXML/duckbill/platypus/INV_3_20090307181658000.xml HTTP/1.0
Content-Type: application/xml
Accept: application/xml
Connection: Close
Content-Length: 388
Host: ppp_peer:21609
112209003343742SOME DESC2.2testVendorID]6161.51.995.58HTTP/1.1 404 Not Found
Cache-Control: private
Content-Type: text/html; charset=utf-8
Server: Microsoft-IIS/8.0
X-SourceFiles: =?UTF-8?B?QzpccHJvamVjdFxnaXRcQ1N0b3JlXEhIUy5BUElcYXBpXGludmVudG9yeVxzZW5kWE1MXGR1Y2tiaWxsXHBsYXR5cHVzXElOVl8zXzIwMDkwMzA3MTgxNjU4MDAwLnhtbA==?=
X-Powered-By: ASP.NET
Date: Thu, 18 Dec 2014 17:23:01 GMT
Connection: close
Content-Length: 5016
IIS 8.0 Detailed Error - 404.0 - Not Found
HTTP Error 404.0 - Not Found
The resource you are looking for has been removed, had its name changed, or is temporarily unavailable.
Most likely causes:
.The directory or file specified does not exist on the Web server. .The URL contains a typographical error. .A custom filter or module, such as URLScan, restricts access to the file.
Things you can try:
.Create the content on the Web server. .Review the browser URL. .Check the failed request tracing log and see which module is calling SetStatus. For more information, click here.
Detailed Error Information:
Module IIS Web Core
Notification MapRequestHandler
Handler StaticFile
Error Code 0x80070002
Requested URL http://ppp_peer:21609/api/inventory/sendXML/duckbill/platypus/INV_3_20090307181658000.xml
Physical Path C:\project\git\CStore\HHS.API\api\inventory\sendXML\duckbill\platypus\INV_3_20090307181658000.xml
Logon Method Anonymous
Logon User Anonymous
Request Tracing Directory C:\Users\clay\Documents\IISExpress\TraceLogFiles\HHS.API
More Information:
This error means that the file or directory does not exist on the server. Create the file or directory and try the request again.
View more information ยป
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
So to recap, "PPP_PEER" does work as a way for the handheld device to describe/contact the PC (it works with the TCP code), and the REST method is reachable from another process (such as Postman), but trying to call the method using PPP_PEER from the handheld device fail with the "404.0 - Not Found" error.
Why?
UPDATE
When I replace "PPP_PEER" with the machine name of the PC, the error changes from "404 - Not Found" to "503 - Service Unavailable":
But that is a bit of a rompecabeza, because the service is obviously available, as it is running and its breakpoint is hit when I call it from Postman.
UPDATE 2
Now this is odd: If I use the full machine name instead of just the "truncated" name, the error goes back to being 404 instead of 503:
So if I use PPP_PEER as the host name, I get a 404; if I use shannon2, I get a 503; if I use shannon2.sscs.ad, I again get 404. Should I blame this on Tim Berners-Lee, Al Gore, Andy Warhol, or someone else?
SO...those are my results on trying to follow Eric Law's first suggestion; there are two others, but: what would I edit the Host header to that might make a difference? Or overwrite it to what?
It seems as if the basic problem is trying to access a "server" app running locally on my PC (even though the handheld != the PC, it is "sort of" the same thing, after a fashion).
Now that the server app is running on a different machine on the network altogether, I'm able to hit it; albeit not yet totally unexceptionally, as can be seen here.

Mono Apache2 HttpWebRequest crashes with "The request timed out"

I am using a payment gateway API in my ASP.Net application. When testing in MonoDevelop with XSP the application works. When I configure it to run in apache2 with mod_mono the code keeps crashing with a timeout error.
I am stumped as to what could change with hosting in Apache instead of XSP. Anyways below is the code that is timing out:
private string SubmitXml(string InputXml)
{
HttpWebRequest webReq = (HttpWebRequest)WebRequest.Create(_WebServiceUrl);
webReq.Method = "POST";
byte[] reqBytes;
reqBytes = System.Text.Encoding.UTF8.GetBytes(InputXml);
webReq.ContentType = "application/x-www-form-urlencoded";
webReq.ContentLength = reqBytes.Length;
webReq.Timeout = 5000;
Stream requestStream = webReq.GetRequestStream();
requestStream.Write(reqBytes, 0, reqBytes.Length);
requestStream.Close();
HttpWebResponse webResponse = (HttpWebResponse)webReq.GetResponse();
using (StreamReader sr = new StreamReader(webResponse.GetResponseStream(), System.Text.Encoding.ASCII))
{
return sr.ReadToEnd();
}
}
The code is crashing on the line: Stream requestStream = webReq.GetRequestStream();
The error returned is:
The request timed out
Description: HTTP 500. Error processing request.
Stack Trace:
System.Net.WebException: The request timed out at
System.Net.HttpWebRequest.GetRequestStream () [0x0005f] in
/private/tmp/monobuild/build/BUILD/mono-2.10.9/mcs/class/System/System.Net/HttpWebRequest.cs:746
at TCShared.PxPay.SubmitXml (System.String InputXml) [0x00048] in
/Users/liam/Projects/techcertain/techcertaincsharp/Components/TCShared/PaymentGateways/Client/PxPay.cs:85
at TCShared.PxPay.GenerateRequest (TCShared.RequestInput input)
[0x00015] in
/Users/liam/Projects/techcertain/techcertaincsharp/Components/TCShared/PaymentGateways/Client/PxPay.cs:69
In my Web.Config I have the following as the request timeout:
<httpRuntime executionTimeout="43200" maxRequestLength="104856" requestValidationMode="2.0" />
I have tried changing the Timeout value on the HttpWebRequest but it still is timing out.
What is causing this to happen and how can I fix it?
I managed to find out why I was experiencing this problem. It is completely unrelated to the use of Apache.
I am using Npgsql for database access to Postgresql. Npgsql comes with two dlls (Npgsql.dll and Mono.Security.dll). For some unknown reason Mono.Security.dll causes the HttpWebRequest to timeout when running on Mono.
Anyways Mono.Security.dll isn't needed when running on Mono because it is already included in the Mono framework. So after removing the Mono.Security dll from my bin directory HttpWebRequest's are now working.
Full credit goes to this post here http://mono.1490590.n4.nabble.com/The-request-timed-out-at-HttpWebRequest-EndGetResponse-td2218213.html .

How to force IIS to send response headers without sending response body and closing connection

I am trying to stream dynamically generated data to a client over HTTP using IIS, and the connection has to remain open for a long period of time, and the server will send periodic status updates to the client while it is performing a time-consuming operation.
This MUST all be handled within ONE request, but I am using a WebClient.OpenRead() stream, which cannot be opened until the headers are sent.
How can I force IIS to send headers to the client, and later send a response body?
This behaviour is normally achievable by setting KeepAlive to true and setting Expect header to "100 and continue". By doing this, server will send the headers with result code 100.
I am not sure if this is possible using WebClient.
Use HttpWebRequest instead to be able to set the values above. In fact WebClient does nothing magical but using GET to get the data. Here is the code for calling OpenRead in Reflector:
try
{
request = this.m_WebRequest = this.GetWebRequest(this.GetUri(address));
Stream responseStream = (this.m_WebResponse = this.GetWebResponse(request)).GetResponseStream();
if (Logging.On)
{
Logging.Exit(Logging.Web, this, "OpenRead", responseStream);
}
stream2 = responseStream;
}
catch (Exception exception)
{
//

HttpWebRequest.GetResponse: "The underlying connection was closed: An unexpected error occurred on a receive."

I've written a C# Windows service (.NET Framework 3.5, C# 3.0) that posts files & HTML form information to a remote server, and then stores the XML server response in a database. Here is the main chunk of pertinent code:
HttpWebRequest request = WebRequest.Create(postUrl) as HttpWebRequest;
request.ProtocolVersion = HttpVersion.Version10;
request.KeepAlive = false;
request.Timeout = 600000;
request.ReadWriteTimeout = 600000;
request.Method = "POST";
request.ContentType = contentType;
request.UserAgent = userAgent;
request.CookieContainer = new CookieContainer();
request.ContentLength = formData.Length;
using (Stream requestStream = request.GetRequestStream())
{
// Push it out there
requestStream.Write(formData, 0, formData.Length);
requestStream.Close();
}
return request.GetResponse() as HttpWebResponse;
My service works properly for all small files, but I get the following error when I try to send larger files (8-9 MB).
The underlying connection was closed: An unexpected error occurred on a receive.
I looked at the outgoing request using Fiddler, and was able to glean the following info:
HTTP/1.1 504 Fiddler - Receive Failure
Content-Type: text/html
Connection: close
Timestamp: 12:25:04.067
ReadResponse() failed: The server did not return a response for this request.
The failure occurs ~7 minutes after I call request.GetResponse(). Is there any way to identify who shut down the connection? And is there anything else I should try on my end to resolve this issue? Thanks in advance!
Since you mention it working for small files, but not larger, I'd suggest checking the max file upload size on the server. I believe the default is 4mb. http://support.microsoft.com/kb/295626
EDIT: Noticed the link above is somewhat out of date. Here's one for iis7: http://www.cyprich.com/2008/06/19/fixing-file-upload-size-limit-in-iis-7/

Categories