I have the WCF client shown below:
public static string Execute(string a)
{
WebHttpBinding b = new WebHttpBinding();
b.Security.Mode = WebHttpSecurityMode.Transport;
WebChannelFactory<IAnimalService> f = new WebChannelFactory<IAnimalService>(b, new Uri(a));
f.Endpoint.Behaviors.Add(new WebHttpBehavior());
IWebService client = f.CreateChannel();
return client.SayHello("moo");
}
I am testing the client (in a console host) against its counterpart service from 2 different computers (A, B) and and i get different outcome. Here are the similarities and differences between A and B:
Both A and B are Windows Server 2012 R2 have multiple network interfaces. And each of them have one interface connected to the Internet (so as to reach the service in question).
When running on machine A, everything works as expected i get expected response ("cow says 'moo'") in the client.
When running on machine B, i get different behaviours:
Via the web-browser (firefox), i can get to the service by constructing a request in the address bar. I can see the request going on the external network interface. And everything works as in 2 above.
Via the app (i.e. code above), i get the exception below and more over, when looking at the request in wireshark, it does not go on the external network interface. The exception comes the fact that on that network interface there is a proxy and the proxy is rejecting the request (X-Squid-Error -> ERR_ACCESS_DENIED 0).
Exception:
Unhandled Exception: System.ServiceModel.Security.MessageSecurityException: The HTTP request was forbidden with client authentication scheme
'Anonymous'. ---> System.Net.WebException: The remote server returned an error: (403) Forbidden.
at System.Net.HttpWebRequest.GetResponse()
at System.ServiceModel.Channels.HttpChannelFactory`1.HttpRequestChannel.HttpChannelRequest.WaitForReply(TimeSpan timeout)
--- End of inner exception stack trace ---
I also consulted the routing table on machine B and it shows that request should have gone on the external network interface. I have assumed that the internal routing table would be consulted by the lower layer of the TCP-IP stack in order to forward the packet to the correct (network) medium.
So, I am wondering if someone would have an idea how i could get my client to pick the correct interface on machine B. I am not sure how to go about to troubleshoot the problem further. So any kind of advice/tips on how to get to the bottom of this situation on machine B would be most welcomed.
Try to use this snippet in you config file, so you will be able to use your default credentials to autenticate in the proxy server.
<system.net>
<defaultProxy useDefaultCredentials="true" />
</system.net>
It would appear that by default, the binding seeks to look for the default proxy setting on machine B. Adding the following binding configuration solved the problem:
b.UseDefaultWebProxy = false;
Related
I am working on a .NET API that runs inside of a docker container. At some point it makes a call to a Python Flask API that is also running in a container.
var response = await httpClient.GetAsync("http://service-name:8000/actual/url")
which then produces the following error:
System.Net.Http.HttpRequestException: Resource temporarily unavailable
---> System.Net.Sockets.SocketException (11): Resource temporarily unavailable
at System.Net.Http.ConnectHelper.ConnectAsync(String host, Int32 port, CancellationToken
cancellationToken)
Has anyone had experience with this before and potentially knows a solution? I cant find much on the web about it at all. I have some seen some mentions of the issue potentially being related to the Flask API not using async methods but that doesnt make sense to me.
The Flask API produces the appropriate responses when accessed through a web browser or Postman using localhost:8000/actual/url and the container logs these responses. I have tried using the localhost URL in the .NET API but that does not work either.
If anymore information is needed please leave a comment and I will do my best to update the post quickly.
-- Christie
TLDR
A reason for the "Resource temporarily unavailable" error is when during name resolution the DNS Server responds with RCODE 2 (Server failure).
Long answer
I noticed the same behavior in a dotnet application running in a dotnet runtime alpine docker container. Here are the results of my investigation:
The error message "Resource temporarily unavailable" corresponds to the EAGAIN error code which gets returned by various functions from the C standard library. At first I suspected the connect() function because the C# stack trace indicates the error happening during the ConnectAsync() call of the c# socket. And indeed the EAGAIN error code appears in the man page of connect() with this description: "No more free local ports or insufficient entries in the routing cache".
I simulated a system with depleted local ports and noticed that a different exception gets thrown in that case, which rules out local port availability as a root cause for the original exception. Regarding the other mentioned cause in the man page it turns out that the routing cache was removed from Linux in 2012. commit
I started to look around for EAGAIN in the source of the musl C lib which is used in the dotnet runtime alpine docker container. After a while I finally noticed the gethostbyname2_r function which is used for resolving a domain name to an ip address via DNS. During System.Net.Sockets.Socket.ConnectAsync() the hostname is still a string and the name resolving happens in native code using the gethostbyname2_r function (or one of its variations).
The final question is: When does gethostbyname2_r return the EAGAIN error code? It's when the RCODE field in the header of the DNS Response has the value 2, which stands for "Server failure". source line 166
To verify this result I ran a simple mock DNS server which always returns the RCODE 2 in the DNS response. The resulting c# exception along with the stack trace matched the original exception exactly.
I'm developing (as a totally no-C#-guy) a web app which communicates with an external data source over OData (server B, some windows 2k12 machine).
The web app runs (is about to run) on an IIS (server A, another windows 2k12 machine), the OData source is a Dynamics NAV 2015 service (the first mentioned windows 2k12 machine, server B).
I'm developing it in VS2013 and if I'm running this locally (meaning: without publishing it, only running it within the local express IIS) it works without any problems at all.
But as soon as I publish it to the target IIS (server A) I'm getting:
An error occurred while processing this request. ---> >System.Data.Services.Client.DataServiceClientException: Unauthorized
at System.Data.Services.Client.QueryResult.ExecuteQuery()
at System.Data.Services.Client.DataServiceRequest.Execute[TElement]>(DataServiceContext context, QueryComponents queryComponents)
--- End of inner exception stack trace ---
This is esentially the piece of code which deals with the OData call:
ODataOrders.NAV odata = new ODataOrders.NAV(new Uri(serviceUri));
System.Net.NetworkCredential nc = new
System.Net.NetworkCredential(_oDataUsername, _oDataUserPassword, _oDataDomain);
odata.Credentials = nc;
DataServiceQuery<ODataOrders.Orders> query =
odata.CreateQuery<ODataOrders.Orders>("Orders");
orderList = query.Execute().ToList(); // "Unauthorized" is being thrown here
It looks like the credentials are being sent/accepted if running from local IIS. And if running from the target (production) server A, the credentials are being somehow lost/overwritten? I really don't know now...
Server A and Server B are in the same domain. My development environment isn't - I can even connect from home through VPN to my work domain and launch my local IIS and still be able to get that request done (the request goes through my local IIS and reaches the Dynamics NAV service so the data is being actually fetched).
Any help would be appreciated...
EDIT
It's Dynamics NAV 2015 CU11.
After some serious hours of reading, programming and trying I've stumbled upon a post here which gave me an idea.
And guess what? It worked - somehow...
Instead of:
System.Net.NetworkCredential(_oDataUsername, _oDataUserPassword, _oDataDomain);
I submitted only:
System.Net.NetworkCredential(_oDataUsername, _oDataUserPassword);
I turns out somehow the domain caused the call not to be authorized (401 error).
We deliver on-premise software that is exposed to the cloud using Azure Service bus relay, the basic code we use to expose is as follows (I have removed everything identifiable):
ServiceHost sh = new ServiceHost(typeof(BasicHttpEntityService));
BasicHttpRelayBinding basicHttpRelayBinding = new BasicHttpRelayBinding();
Uri uriEndPointAddress = ServiceBusEnvironment.CreateServiceUri("https", "ourdomain", "test-url-appendage");
m_shRelayServiceHost.AddServiceEndpoint(
typeof(IMyService),
basicHttpRelayBinding,
uriEndPointAddress
).Behaviors.Add(
new TransportClientEndpointBehavior
{
TokenProvider = TokenProvider.CreateSharedSecretTokenProvider(
"MyUser",
"MyPassword")
});
sh.Open();
This works fine at most of our customers, however, one of our customers has a strict firewall policy.
According to the SB guidelines we have found, we asked them to open ports 9351-9354 to ourdomain.servicebus.windows.net. Now we find out that when there is an incoming request, the service connects to both 'ourdomain' (we see this succeeds in Wireshark, and also in the WCF log) AND an unknown (to us) service on 40.112.124.x:9352 (the last octet changes with every request).
I have been able to reproduce the problem in my development environment by disallowing connections to any 40.x.x.x address on any port. This is what happens in the WCF log:
System.Net.Sockets.SocketException (0x80004005): An attempt was made to access a socket in a way forbidden by its access permissions 40.112.124.25:9352
Server stack trace:
at System.Net.Sockets.Socket.EndConnect(IAsyncResult asyncResult)
at Microsoft.ServiceBus.RelayedConnectionSession.ConnectAsyncResult.<GetAsyncSteps>b__4(ConnectAsyncResult thisRef, IAsyncResult r)
at Microsoft.ServiceBus.Messaging.IteratorAsyncResult`1.StepCallback(IAsyncResult result)
Exception rethrown at [0]:
at Microsoft.ServiceBus.Common.AsyncResult.End[TAsyncResult](IAsyncResult result)
at Microsoft.ServiceBus.RelayedConnectionSession.EndConnect(IAsyncResult result)
There is no DNS-request going out during this time, so there is no host name that provides any clues to the function of this outgoing connection.
From my investigation, this appears to be a Microsoft controlled subnet, so I'm fine with the relay service connecting to it, but I would like to know:
Is this additional connection optional?
If not, should we allow the entire subnet?
Could this IP-range change in the future? Is it hardcoded somewhere?
In the end, we requested support from Microsoft.
In short their answers were as follows:
Is this additional connection optional?
No it is not optional. For the relay listener, there is a control channel on port 5671, this connection is always there. Then there is a data channel on portal 9352, this connection established when there is a relay client tries to communicate with the listener.
Could this IP-range change in the future?
Currently, for relay this IP can change, so you need to allow the IP range for the entire datacenter in your region (https://www.microsoft.com/en-us/download/confirmation.aspx?id=41653). The SB product team will be working on to significantly reduce this IP range in the future, to make it much more predictable. There is no exact ETA on this future.
So the good news is they are working on it. The bad news is, that right now, we will need to add a LOT of IP addresses to the white-list to ensure smooth operation.
I can use this program on my own computer, but I can not use on the server.
Server use supreme authority Administrator to open the program.
Server WCF HTTP Activation Feature with .NET4.5 is opening.
Server endpoint address use "http://localhost" like following
endpoint address="http://localhost" binding="basicHttpBinding" bindingConfiguration="NewBinding0" name="ProductService" contract="ProductService.IWCFProductService"
Wrong Message:
The communication object, System.ServiceModel.ServiceHost, cannot be used for communication because it is in the Faulted state.
Stack trace at System.ServiceModel.Channels.CommunicationObject.Close(TimeSpan timeout)
at System.ServiceModel.ServiceHostBase.System.IDisposable.Dispose()
at FileUtilityHelperService.Program.Main(String[] args)
This simply means that there has been an unexpected exception somewhere in your code. The error message "...because it is in the Faulted state" means that communication between the server and the client is unusable.
What you need is better error handeling.
Use try/catch around your code that can potentially generate an exception
Always order exeptions from the most specific to the least specific
You would probably like to log your errors to a file or database, log4net is great for this (and comes as a nuget package)
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
}