We have a REST API which maps third-party proprietary language codes (in the en-US format) into language codes that our own system recognises. The REST API's route is
~/v1/languages/mappings/{foreignLanguageCode} [GET]
We receive these third-party language codes and send them to our own API using an instance of System.Net.Http.HttpClient.
This is working perfectly well for many language codes but when passed ko-US the request doesn't even get sent - the HttpClient object throws the exception
An error occurred while sending the request.
The inner exception - a WebException - says
The server committed a protocol violation. Section=ResponseStatusLine
The exception also contains
Source: "System"
Status: ServerProtocolViolation
StackTrace:
at System.Net.HttpWebRequest.EndGetResponse(IAsyncResult asyncResult)
at System.Net.Http.HttpClientHandler.GetResponseCallback(IAsyncResult ar)
The URI at this point is
https://www.example.com/api/v1/languages/mappings/ko-US/
I've tried it with and without that trailing slash: no difference. We can send many other language codes to the same API without any problem.
Can anyone explain why this particular URI causes this exception?
Answering my own question...
I can't really explain why but this solved the problem:
myHttpClient.DefaultRequestHeaders.ConnectionClose = true;
I added that immediately before sending the request, so the working code looks like this:
httpClient.DefaultRequestHeaders.ConnectionClose = true;
var response = await httpClient.GetAsync(uri).ConfigureAwait(false);
Related
I am working on a .Net Standard class library and working on creating a library for the new Destiny 2 Api. I have one method working which is the search for a user to get their information. However, when I make a request to a different endpoint I get this error:
System.AggregateException: One or more errors occurred. --->
System.Net.Http.HttpRequestException: Error while copying content to a
stream. ---> System.IO.IOException: The read operation failed, see
inner exception. ---> System.Net.Http.WinHttpException: The operation
has been canceled
I can send this request just fine using PostMan or any other Api testing tool so something must be wrong with my code. Something worth noting, when using other Api tools I notice that I get redirected a few times. Also when using Fiddler I can see that none of the requests actually get Json back, they all look like redirects to another page, Postman shows 3 redirects fiddler shows 2 and then a failure in my code.
My code is pretty small so I cannot think of much that could be breaking it:
public string GetProfile(BungieMembershipType membershipType, string destinyMembershipId)
{
var properUrl = String.Format(GetProfileUrl, (int)membershipType, destinyMembershipId);
var rawData = RootRequest.Web.GetStringAsync(properUrl).Result;
return rawData;
}
The only thing that seems odd to me is I am testing my code inside of Unit Tests, I cannot evaluate RootRequest during the debugging. RootRequest is a static class that has a static HttpClient on it that is used for making all requests to keep authentication to the Api simple.
I would assume that something is actually wrong internally at the Bungie Api servers but multiple things about my code had to change. Firstly, my BaseUri was missing the www.. Secondly, the GetProfileUrl was missing a / before the ?queryString was added.
There are numerous posts on how to check if a URL is valid. All of them feature basically the same code, which seems to work for everyone - not for me though and I don't get why.
public static bool ifURLexists(string url)
{
try
{
var request = WebRequest.Create(url) as HttpWebRequest;
request.Method = "HEAD";
//response ALWAYS throws an exception
using (var response = (HttpWebResponse)request.GetResponse())
{
return response.StatusCode == HttpStatusCode.OK;
}
}
catch
{
return false;
}
}
I have tested the method with parameters such as "http://www.nonexistingwebsiteblabla.com" and "http://www.google.com". No matter if I insert an existing or a non existing URL, I get a WebException at this line:
using (var response = (HttpWebResponse)request.GetResponse())
Why could it be not working?
Check the status WebException.Status
This will let you know what specific web exception has occured.
Update: Try change the request.Method = "HEAD";
to GET and try.
Try with a unavailable (404) url, compare the status. Check whether anything is blocking your request.
This is how i manage in my code, i am handling using only ftp specific status.'CommStatus' is an ENUM with error codes which is available in whole application.
catch (WebException ex)
{
FtpWebResponse response = (FtpWebResponse)ex.Response;
switch(response.StatusCode)
{
case FtpStatusCode.ActionNotTakenFileUnavailable:
return CommStatus.PathNotFound;
case FtpStatusCode.NotLoggedIn:
return CommStatus.AuthenticationError;
default: return CommStatus.UnhandledException;
}
}
Below are the available Status of WebException.
CacheEntryNotFound
This API supports the product infrastructure and is not intended to be used directly from your code. The specified cache entry was not found.
ConnectFailure
This API supports the product infrastructure and is not intended to be used directly from your code. The remote service point could not be contacted at the transport level.
ConnectionClosed
This API supports the product infrastructure and is not intended to be used directly from your code. The connection was prematurely closed.
KeepAliveFailure
This API supports the product infrastructure and is not intended to be used directly from your code. The connection for a request that specifies the Keep-alive header was closed unexpectedly.
MessageLengthLimitExceeded
This API supports the product infrastructure and is not intended to be used directly from your code. A message was received that exceeded the specified limit when sending a request or receiving a response from the server.
NameResolutionFailure
This API supports the product infrastructure and is not intended to be used directly from your code. The name resolver service could not resolve the host name.
Pending
This API supports the product infrastructure and is not intended to be used directly from your code. An internal asynchronous request is pending.
PipelineFailure
This API supports the product infrastructure and is not intended to be used directly from your code. The request was a piplined request and the connection was closed before the response was received.
ProtocolError
This API supports the product infrastructure and is not intended to be used directly from your code. The response received from the server was complete but indicated a protocol-level error. For example, an HTTP protocol error such as 401 Access Denied would use this status.
ProxyNameResolutionFailure
This API supports the product infrastructure and is not intended to be used directly from your code. The name resolver service could not resolve the proxy host name.
ReceiveFailure
This API supports the product infrastructure and is not intended to be used directly from your code. A complete response was not received from the remote server.
RequestCanceled
This API supports the product infrastructure and is not intended to be used directly from your code. The request was canceled, the WebRequest.Abort method was called, or an unclassifiable error occurred. This is the default value for Status.
RequestProhibitedByCachePolicy
This API supports the product infrastructure and is not intended to be used directly from your code. The request was not permitted by the cache policy. In general, this occurs when a request is not cacheable and the effective policy prohibits sending the request to the server. You might receive this status if a request method implies the presence of a request body, a request method requires direct interaction with the server, or a request contains a conditional header.
RequestProhibitedByProxy
This API supports the product infrastructure and is not intended to be used directly from your code. This request was not permitted by the proxy.
SecureChannelFailure
This API supports the product infrastructure and is not intended to be used directly from your code. An error occurred while establishing a connection using SSL.
SendFailure
This API supports the product infrastructure and is not intended to be used directly from your code. A complete request could not be sent to the remote server.
ServerProtocolViolation
This API supports the product infrastructure and is not intended to be used directly from your code. The server response was not a valid HTTP response.
Success
This API supports the product infrastructure and is not intended to be used directly from your code. No error was encountered.
Timeout
This API supports the product infrastructure and is not intended to be used directly from your code. No response was received during the time-out period for a request.
TrustFailure
This API supports the product infrastructure and is not intended to be used directly from your code. A server certificate could not be validated.
UnknownError
This API supports the product infrastructure and is not intended to be used directly from your code. An exception of unknown type has occurred.
More details here: https://msdn.microsoft.com/en-us/library/system.net.webexceptionstatus(v=vs.110).aspx
Also you can use this option.
IPHostEntry ipHost = Dns.GetHostEntry(url);
I'm developing a Windows Phone 8 app that consumes a web service. This particular web service requires a GET request with an entity body.
I'm using the System.Net.Http.HttpClient to send this request, which I've successfully used to send various other web requests (GETs, POSTs, and PUTs). This is the first GET request that includes a payload and therefore includes a Content-Type and Content-Length header.
The request fails with an exception like the following:
'TaskHost.exe' (CLR C:\windows\system32\coreclr.dll: Silverlight AppDomain): Loaded 'C:\windows\system32\en-US\mscorlib.debug.resources.dll'. Module was built without symbols.
An exception of type 'System.Net.ProtocolViolationException' occurred in System.Windows.ni.dll and wasn't handled before a managed/native boundary
A first chance exception of type 'System.Net.ProtocolViolationException' occurred in mscorlib.ni.dll
An exception of type 'System.Net.ProtocolViolationException' occurred in mscorlib.ni.dll and wasn't handled before a managed/native boundary
Including a payload with a GET request is a bit unusual although according to my research, not expressly forbidden by the RFCs.
I don't have the option of changing the web service. Does System.Net.Http.HttpClient outright not allow a GET with an entity body? If not, are there any work-arounds?
Thank you.
I know it's a while since you asked this but here goes anyway.
While sending a payload in the body of a GET request may not violate the RFC's client-side, it does go against common practice. What the RFC's do say is that a server fielding such a request is in no way obliged to look at anything other than the request URI and the Host: header in order to determine what its response should be.
Quoting from the HTTP 1.1 specification in RFC2616, section 5.2 says: "The exact resource identified by an Internet request is determined by examining both the Request-URI and the Host header field." It says nothing about a request body.
This means that, even if what you're attempting to do is not in violation of any RFC, the web service consumed by your WP8 app is. If you have no option but to use it then it's looking like you're going to have to roll out your own HTTP-ish client, which I'm guessing you've probably already done by now. The off-the-shelf solution in System.Net.Http.HttpClient isn't going to exhibit behaviour that will never be of use while communicating with a compliant server.
I am accessing a web server that requires a custom protocol rather than http in the url. I have tried to register my protocol, but there isn't much documentation on how to get this to work. The web server serves up standard HTTP responses, but if the request isn't prepended with custom:// instead of http://, it won't work. I would like to just use the WebRequest underlying functionality as is since this is ultimately HTTP, however, I need a way to submit the request with my custom protocol url. I register it like this:
WebRequest.RegisterPrefix("custom", new CustomWebRequestCreator());
But then, when I go to create a WebRequest, while it returns my custom class after this code:
Uri uri = new Uri("custom://192.168.0.122:94934/resource");
System.Net.WebRequest request = WebRequest.Create(uri);
The debugger says that the request is actually my custom class, but then I get this exception:
System.NotImplementedException was unhandled
HResult=-2147467263
Message=This method is not implemented by this class.
Source=System
StackTrace:
at System.Net.WebRequest.GetResponse()
...
When I try to just pass my URL to WebRequest.Create() without registering the prefix, I get this exception:
System.NotSupportedException was unhandled
HResult=-2146233067
Message=The URI prefix is not recognized.
Source=System
StackTrace:
at System.Net.WebRequest.Create(Uri requestUri, Boolean useUriBase)
at System.Net.WebRequest.Create(Uri requestUri)
...
Any idea how I might get this to work?
It doesn't seem possible, or would be reaching the level of complexity of re-implementing HTTP for WebRequest from scratch.
I suggest you instead create a TCP relay, which you connect to using WebRequest [http://localhost/resource], in order to make it work without trying to contort WebRequest. The relay would in turn forward to TCP socket 192.168.0.122:94934.
With a relay, you use the common and simplified WebRequest object. If it's for a console/webforms applicaiton, the relay can be started on another thread (or can be started asynchronously), when the application is started.
I am getting this error:
Client found response content type of 'text/html', but expected 'text/xml.
I am adding web reference for live search. When i build the project its Successful. But after that once i enter some text in textbox & enter search button it gives this error. I am Using my local machine & Using .net 2.0 with C#.
Plz help me...
Thanks In Advance...
As Matt said, it's probably an error page coming back.
Either use a proxy like Fiddler or a network sniffer like WireShark to see what the raw response is - that should help you get to the bottom of what's going on.
Generally that error means that the service has sent back an (HTML) error message rather than the XML SOAP response that your client was expecting.
For web services that you control it's really easy to find the problem, because you can invoke the webmethods by hand in your browser. To diagnose it when it's someone else's service is a little trickier. You might be able to trace into the code for your web reference and inspect the text of the response before the exception is thrown.
I have found Fiddler to be highly useful in debugging http client server issues.
It is a proxy that allows you to intercept and even change the content of the request and response.
In your actual code, replace the line:
searchRequest.AppID = "APP ID you generated from ...";
with the actual AppID, which should be a long alpha-numeric sequence.