How to detect that a WebRequest failed due to a web proxy error and not a target web server error?
try
{
var request = (HttpWebRequest)WebRequest.Create("http://www.example.com");
request.Proxy = new WebProxy("localhost");
var response = request.GetResponse();
return response.GetResponseStream();
}
catch(WebException webex)
{
//Detect proxy failure
}
It is difficult. Here are some suggestions:
The webex.Response.ResponseUri property contains the URI of your proxy server instead of the server you were trying to contact.
The webex.Response.StatusCode property is one that always refers to a proxy problem, e.g. ProxyAuthenticationRequired. Unfortunately most statuses could refer to either a proxy error or a server error.
The webex.Response.Headers collection contains non-standard entries that you recognise as being generated by your proxy server. For example, the Squid proxy returns the header "X-Squid-Error", with its own proprietary set of statuses.
The webex.Response.ResponseStream stream contains an HTML or plain text error message in a format that you recognise as being generated by your proxy server. You might test to see if it contains the URI of your proxy server.
In your catch block, make sure that you log full details of the WebException object, including all the properties mentioned above. You can then analyse the log data and develop an accurate test for proxy errors.
I think you could catch InvalidOperationException and then check the message for "proxy".
The message would say:
The proxy name could not be resolved: 'localhost'
Related
We are running into a situation where sendAsync post call from a server is not working. Here's my scenario
We have a Web API hosted on a server outside our internal network (DMZ) which has a simple GET implemented to it as
Public HttpResponseMessage Get(strind id){ (API 1)
//do some work
using(HttpClient client = new HttpClient()){
//We Invoke another web API which is hosted inside our network and do a post // as
HttpRequestMessage message = new HttpRequestMessage(HttpMethod.Post, url);
message.Content = new StringContent(someStr);
message.Content.Header.ContentType = new MediaTypeHeaderValue("application/json");
try{
var response = client.SendAsync(message).Result (API 2)
}
catch(Exception e){
//Something
}
}
The post SendAsync().Results fails with the following exception
at System.Threading.Tasks.Task`1.GetResultCore(Boolean waitCompletionNotification) and the message says as One or More errors Occurred.
The innerexception is also not telling anything good. It just InnerException.StackTrace is coming blank and the InnerException.Message is An error occurred while sending request.
In order to test the communication, we ran a GET request from the external sever for API 2 and it worked fine but the POST's are not working.
Everything works fine when both the API's (the one for get and the other one that does the post) are hosted on our internal servers.
Any Suggestions why this might not be working when executed from the external server?
Short answer: Regardless of what I'm betting on, you have to inspect those inner exceptions and find out the exact message.
Longer answer:
The fact that when you host the application in your internal network, the code works (the POST call is successful) and when moved to DMZ it fails strongly indicates the server making the call has no access to the remote endpoint.
I'd bet on the lack of network connectivity between your App Server and the API 2.
I have some code that calls HttpWebRequest's GetResponse() method to retrieve HTML from a URL and return it to the calling method.
This has been working perfectly fine within my Development and QA environments but now that I have uploaded it to my UAT server, I keep getting the following error:
The remote server returned an error: (404) Not Found.
The main difference between Dev/QA and UAT is that UAT uses SSL/HTTPS based URLs whereas Dev/QA uses HTTP. I introduced the following line of code to help progress me a little futher:
ServicePointManager.ServerCertificateValidationCallback = new System.Net.Security.RemoteCertificateValidationCallback(AcceptAllCertifications);
where AcceptAllCertifications always returns true but I still get my 404 error.
I that people who previously had this error have been able to resolve the issue by merely ensuring the URI used for the HttpWebRequest doesn't have a slash at the end (see: Simple HttpWebRequest over SSL (https) gives 404 Not Found under C#) but this does not make a difference to me.
I have now tried what was suggested at this post (see: HttpWebResponse returns 404 error) where I render the exception on the page. This bypassed the yellow-warning screen and gives me a bit more informtion, including the URL it is trying to get a response from. However, when I copy and paste the URL into my browser, it works perfectly fine and renders the HTML on the page. I'm quite happy therefore that the correct URL is being used in the GetResponse call.
Has anyone got any ideas as to what may be causing me this grief? As said, it only seems to be a problem on my UAT server where I am using SSL.
Here is my code to assist:
public static string GetHtmlValues()
{
var webConfigParentUrlValue = new Uri(ConfigurationManager.AppSettings["ParentUrl"]);
var destinationUrl = HttpContext.Current.Request.Url.AbsoluteUri;
var path = "DestinationController" + "/" + "DestinationAction" + "?destinationUrl=" + destinationUrl;
var redirect = new Uri(webConfigParentUrlValue, path).AbsoluteUri;
ServicePointManager.ServerCertificateValidationCallback = new System.Net.Security.RemoteCertificateValidationCallback(AcceptAllCertifications);
var request = (HttpWebRequest)WebRequest.Create(redirect);
//Ensures that if the user has already signed in to the application,
// their authorisation is carried on through to this new request
AttachAuthorisedCookieIfExists(request);
HttpWebResponse result;
try
{
result = (HttpWebResponse)request.GetResponse();
}
catch (WebException ex)
{
result = ex.Response as HttpWebResponse;
}
String responseString;
using (Stream stream = result.GetResponseStream())
{
StreamReader reader = new StreamReader(stream, Encoding.UTF8);
responseString = reader.ReadToEnd();
}
return responseString;
}
More details of the error as it is rendered on the page:
I ran into a similar situation, but with a different error message. My problem turned out to be that my UAT environment was Windows 2008 with .NET 4.5. In this environment the SSL handshake/detecting is performed differently than most web browsers. So I was seeing the URL render without error in a web browser but my application would generate an error. My error message included "The underlying connection was closed: An unexpected error occurred on a send". This might be your issue.
My solution was to force the protocol change. I detect the specific error, then I force a change in the security protocol of my application and try again.
This is the code I use:
catch (Exception ex)
{
if(ex.Message.Contains("The underlying connection was closed: An unexpected error occurred on a send."))
{
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3;
// retry the retrieval
}
}
I finally found the solution to my problem...
The first clue to get me on the right track was the wrong physical path being displayed in the 404 error from IIS. It turns out that this incorrect physical path was mapped to another site in my IIS setup. This particular naturally had a binding also; port 443. As you may know, port 443 is the default port for https.
Now looking at my URL that I was trying to pass into the HTTPWebRequest.GetResponse() method, it looked something like this:
https://www.my-web-site.com
Taking this into account, when this application was hosted on IIS within the bounds of SSL, the error was occuring as follows:
Code enters the aforementioned method GetHtmlValues()
The code gets https://www.my-web-site.com from the web.config file
A response is requested from https://www.my-web-site.com
At this point, as no port has been specified and application is now out there on the open internet, it tries to get a response from https://www.my-web-site.com:443
The problem is, my application isn't hosted via IIS on port 443. A different application lives here. Subsequently, as the page can't be found on port 443, a 404 error is produced.
Now for the solution...
Looking in IIS, I found the port that my application sits on. Let's say port 16523.
Whereas previously in my web.config I had my key of ParentUrl decalred with a value of https://www.my-web-site.com, this is to be changed to http://www.my-web-site.com:16523
Note how the https has become http and the port number is specified at the end. Now when the application tries to get the response, it no longer uses the default ssl port as the correct one was specified.
I want to monitor a WCF server, and send email notification if the server is down. To accomplish that, I am writing a console app to periodically send dummy request to the server, and check if response is sent back. When the console app received exception the server has issues, including the server being down.
However, the problem is that I received different exception on different status of the server. Below is the exceptions returned from the server when it is on different status. However, all seem belong to server down category. Any idea??:
When IIS is turned off
System.ServiceModel.EndpointNotFoundException,
Message:
There was no endpoint listening at http://localhost/service.svc that could accept the message. This is often caused by an incorrect
address or SOAP action. See InnerException, if present, for more
details.
Inner Exception Message:The remote server returned an error: (404) Not Found
When a Web.config file is deliberately changed to a wrong name:
System.ServiceModel.ServiceActivationException
Link:
http://localhost/service.svc
Message:
The requested service, 'http://localhost/service.svc' could not be activated. See the server's diagnostic trace logs for more
information.
For other unknown reason
System.ServiceModel.ServerTooBusyException
Message:
The HTTP service located at http://localhost/service.svc' is too busy.
Message:
The remote server returned an error: (503) Server Unavailable.
Update 1
The exception does NOT always return http status code.
Update 2
Apart from using WCF proxy to call the service, I have to use WebRequest too, as below:
try
{
WebRequest webRequest = WebRequest.Create(uri);
webRequest.Method = "GET";
HttpWebResponse httpWebResponse = (HttpWebResponse)webRequest.GetResponse();
}
catch () //what excpetion will tell me server is down??
{
...
}
The actual content of the error shouldn't really be of consequence - unless you're monitoring individual operations on the service (i.e. should a POST with some data to a particular URL return a specific response) - realistically, then, you're just going to be looking at the status code itself; and for that you want to look through all the HTTP Status Codes and see those which look like errors as far as you're concerned.
As a good starting point - you might want to consider nearly all of the 5xx codes; as they are all connected with server errors.
You might also want to consider some of the 4xx codes (although these are usually connected with clients, so be ruthless). In particular:
400 - Bad Request - so long as you can be sure that the server should be able to understand the request
404 - Not Found - if you're sure that the given URL should be present
405 - Method Not Allowed - if you're sure that the given HTTP verb should be supported (e.g. a POST or DELETE)
For some of the narrower 4xx codes, e.g. 413 Request Entity Too Large or 414 Request-URI Too Long; these could conceivably happen after days or months of normal operation due to things like security updates. In which case you're not necessarily identifying that the service is down as such, but you might be anticipating it being unable to perform it's intended function.
Any HTTP status result code in the 400 or 500 series is a problem that will prevent you're request from processing. All of these errors derive from System.ServiceModel.CommunicationException so check for that.
I am using chilkat socket class. The problem is I want to keep my socket open, lets say I executed my form and the very first time which opened the port on a specific IP to listen the messages.I am able to receive the messages first time only successfully, now after this message I want to keep my application to keep listening and receive when ever a new message comes.
We have several clients who will connect and send some text messages on the same port and ip.
But I am unable to achieve this. I need to build a Listener, which will keep on listening and as soon as I will get any message I need to process it. Any body who has used chilkat class or having experience in this kind of application kindly suggest me how can I achieve this functionality as I could't find good example for this kind of application on CHILKAT website or may be I am inexperienced don't know how to exactly code this type of functionality.
Edit 1: Jermy,
yes we have developed REST WCF services and they are working perfect, but the problem is in the response of REST WCF Service big response headers are appearing, which we don't want because in our enterprise application Windows Phone 7 mobiles will also communicate and send text messages and only for the sake of mobiles we are trying to reduce the data we need to pass back and by using sockets we can avoid extra response headers and SMS is not an option for us because of cost. If you have any suggestions towards Webservices to minimize the data kindly share it.
Have you considered a Web Service? They can be consumed by pretty much any language that can send Http requests. If you have control of the client applications then a Web Service is definitely the correct route.
http://sarangasl.blogspot.com/2010/09/create-simple-web-service-in-visual.html
Edit:
Have you considered simple http upload of bytes, with a http response code. Ie Http Ok, Http Failure. You can customize the status codes to anything that suits your project.
Edit 2:
Perhaps an RPC styled method with ONLY http status codes as the response could be suitable. Checks this question for hints. json call with C#
Basically you are just sending some string to a url, then receiving the status code back. That is quite minimal.
Edit 3:
Here is something I pulled out of some old code with Reflector. This is just for the general gist of the procedure. Obviously there should be a using statement on the first request.
public void SMS(Uri address, string data)
{
// Perhaps string data is JSON, or perhaps its something delimited who knows.
// Json seems to be the pretty lean.
try
{
HttpWebRequest request = (HttpWebRequest) WebRequest.Create(address);
request.Method = "POST";
// If we don't setup proxy information then IE has to resolve its current settings
// and adds 500+ms to the request time.
request.Proxy = new WebProxy();
request.Proxy.IsBypassed(address);
request.ContentType = "application/json;charset=utf-8";
// If your only sending two bits of data why not add custom headers?
// If you only send headers, no need for the StreamWriter.
// request.Headers.Add("SMS-Sender","234234223");
// request.Headers.Add("SMS-Body","Hey mom I'm keen for dinner tonight :D");
request.Headers.Add("X-Requested-With", "XMLHttpRequest");
StreamWriter writer = new StreamWriter(request.GetRequestStream());
writer.WriteLine(data);
writer.Close();
using (HttpWebResponse response = (HttpWebResponse) request.GetResponse())
{
using (Stream stream = response.GetResponseStream())
{
// Either read the stream or get the status code and description.
// Perhaps you won't even bother reading the response stream or the code
// and assume success if no HTTP error status causes an exception.
}
}
}
catch (WebException exception)
{
if (exception.Status == WebExceptionStatus.ProtocolError)
{
// Something,perhaps a HTTP error is used for a failed SMS?
}
}
}
Remember to respond only with Http status codes and descriptions. And ensure that the request's proxy is setup to bypass the requesting Url to save time resolving the IE proxy.
Is there a way to get a System.Net.WebRequest or System.Net.WebClient to respect the hosts or lmhosts file?
For example: in my hosts file I have:
10.0.0.1 www.bing.com
When I try to load Bing in a browser (both IE and FF) it fails to load as expected.
Dns.GetHostAddresses("www.bing.com")[0]; // 10.0.0.1
WebRequest.Create("http://10.0.0.1").GetResponse(); // throws exception (expected)
WebRequest.Create("http://www.bing.com/").GetResponse(); // unexpectedly succeeds
Similarly:
WebClient wc = new WebClient();
wc.DownloadString("http://www.bing.com"); //succeeds
Why would System.Net.Dns respect the hosts file but System.Net.WebRequest ignore it? What do I need to change to make the WebRequest respect the hosts file?
Additional Info:
If I disable IPv6 and set my IPv4 DNS Server to 127.0.0.1, the above code works (fails) as expected. However if I add my normal DNS servers back as alternates, the unexpected behavior resumes.
I've reproduced this on 3 Win7 and 2 Vista boxes. The only constant is my company's network.
I'm using .NET 3.5 SP1 and VS2008
Edit
Per #Richard Beier's suggestion, I tried out System.Net tracing. With tracing ON the WebRequest fails as it should. However as soon as I turn tracing OFF the behavior reverts to the unexpected success. I have reproduced this on the same machines as before in both debug and release mode.
Edit 2
This turned out to be the company proxy giving us issues. Our solution was a custom proxy config script for our test machines that had "bing.com" point to DIRECT instead of the default proxy.
I think that #Hans Passant has spotted the issue here. It looks like you have a proxy setup in IE.
Dns.GetHostAddresses("www.bing.com")[0]; // 10.0.0.1
This works because you are asking the OS to get the IP addresses for www.bing.com
WebRequest.Create("http://www.bing.com/").GetResponse(); // unexpectedly succeeds
This works because you are asking the framework to fetch a path from a server name. The framework uses the same engine and settings that IE frontend uses and hence if your company has specified by a GPO that you use a company proxy server, it is that proxy server that resolves the IP address for www.bing.com rather than you.
WebRequest.Create("http://10.0.0.1").GetResponse(); // throws exception (expected)
This works/fails because you have asked the framework to fetch you a webpage from a specific server (by IP). Even if you do have a proxy set, this proxy will still not be able to connect to this IP address.
I hope that this helps.
Jonathan
I'm using VS 2010 on Windows 7, and I can't reproduce this. I made the same hosts-file change and ran the following code:
Console.WriteLine(Dns.GetHostAddresses("www.bing.com")[0]); // 10.0.0.1
var response = WebRequest.Create("http://www.bing.com/").GetResponse(); // * * *
Console.WriteLine(new StreamReader(response.GetResponseStream()).ReadToEnd());
I got an exception on the line marked "* * *". Here's the exception detail:
System.Net.WebException was unhandled
Message=Unable to connect to the remote server
Source=System
StackTrace:
at System.Net.HttpWebRequest.GetResponse()
at ConsoleApplication2.Program.Main(String[] args) in c:\Data\Projects\ConsoleApplication2\ConsoleApplication2\Program.cs:line 17
InnerException: System.Net.Sockets.SocketException
Message=A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond 10.0.0.1:80
Source=System
ErrorCode=10060
Maybe it's an issue with an earlier .NET version, that's now fixed in .NET 4 / VS 2010? Which version of .NET are you using?
I also found this thread from 2007, where someone else ran into the same problem. There are some good suggestions there, including the following:
Turn on system.net tracing
Work around the problem by using Dns.GetHostAddresses() to resolve it to an IP. Then put the IP in the URL - e.g. "http://10.0.0.1/". That may not be an option for you though.
In the above thread, mariyaatanasova_msft also says: "HttpWebRequest uses Dns.GetHostEntry to resolve the host, so you may get a different result from Dns.GetHostAddresses".
You should overwrite the default proxy.
HttpWebRequest & WebRequest will set a default proxy if present in Internet Explorer and your file hosts will be bypassed.
request.Proxy = new WebProxy();
The following is just an example of code:
try
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("www.bing.com");
request.Proxy = new WebProxy();
request.Method = "POST";
request.AllowAutoRedirect = false;
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
if (response.StatusCode == HttpStatusCode.OK)
{
//some code here
}
}
catch (exception e)
{
//Some other code here
}