Does RestSharp perform WINS lookup? - c#

I am trying to connect to an API deployed on a Windows server that does not belong to a domain.
When I initialize my RestClient this way my requests fail. If I provide my machine's IP address, my request works properly.
var options = new RestClientOptions("https://MyMachine/") {
Timeout = 1000
};
var client = new RestClient(options);
My guess is, RestSharp only performs DNS lookup and not WINS lookup. Is my guess right?

Thank you very much for your input, it has been helpful to understand that I was on the wrong track.
I solved my issue by adding the following line:
ServicePointManager.EnableDnsRoundRobin = true;

Related

How do I decrease DNS refresh timeout successfully with HttpClient in Xamarin Forms?

I'm working on a fairly complex Xamarin.Forms application. We make a lot of REST requests. It's been reported that our application isn't respecting DNS failover for load balancing in a timely manner, so I started investigating. I'm running dnsmasq so I can look at when the app makes DNS requests. The code is currently using HttpWebRequest, and I noticed it's making DNS queries at least 10 minutes apart.
I understand part of this is because most .NET networking bits use a keepalive connection. I certainly see a higher rate of DNS queries if I force the headers to not use keepalive, but that adds network overhead so it's not a desirable solution. But I didn't initially see a clear way to control how HttpWebRequest makes DNS queries.
It looked promising that I could get its ServicePoint property and set the ConnectionLeaseTimeout on that. Unfortunately, that throws NotImplementedException in Xamarin so it's not going to be part of any solution.
I thought that perhaps HttpClient would be more configurable. I see a lot of discussion about how to use it properly, and that if you do it that way you need to set ServicePointManager.DnsRefreshTimeout to a smaller value for use cases where you want to expect DNS to update frequently. But this is usually done in conjunction with getting the ServicePoint for the deisred endpoint and also modifying ConnectionLeaseTimeout, which isn't possible.
I've been testing with a very simple app that reuses an HttpClient and makes the same request any time I push a button. Slap this ViewModel behind some Xaml with a button:
using System;
using Xamarin.Forms;
using System.Net.Http;
using System.Net;
namespace TestDns {
public class MainPageViewModel {
private const string _URL = "http://www.example.com";
private HttpClient _httpClient;
private ServicePoint _sp;
public MainPageViewModel() {
var sp = ServicePointManager.FindServicePoint(new Uri(_URL));
_sp = sp;
//_sp.ConnectionLeaseTimeout = 100; // throws NIE
_httpClient = new HttpClient();
ServicePointManager.DnsRefreshTimeout = 100;
}
public Command WhenButtonIsClicked {
get {
return new Command(() => SendRequest());
}
}
private async void SendRequest() {
Console.WriteLine($"{_sp.CurrentConnections}");
var url = "http://www.example.com";
var response = await _httpClient.GetAsync(url);
Console.WriteLine($"{response.Content}");
}
}
}
I didn't expect ConnectionLeaseTimeout to throw. I expected this code to only cache DNS requests for 100ms, I was going to choose a more reasonable timeframe like 2-3 minutes in more production-oriented tests. But since I can't get this simple example to function like I want, it seems moot to increase the delays.
Surely someone else has had this problem in a Xamarin app? Is my only solution going to be to look deeper and try to use native networking constructs?
If you're doing this on Android, DNS is cached for 10 minutes, and I don't believe you have any access to the expiration/refresh time from inside of your app. There are a number of ways to force a refresh but they all involve user actions like going into Network Connections and flipping from Static to DHCP and back, etc.
The only way I can think of to be sure of getting a fresh DNS lookup from inside your app is to have 10+ minutes worth of DNS entries that all alias to your server, and cycle your app through them, so every time you ask for a DNS lookup, it's a new name and not in the cache.
For example, look for 1.server.example.com 2.server.example.com, etc. Each new name will force a new lookup and won't be pulled from the cache because it's not there.
It seems that Java has decided the solution to "some people implement DNS improperly and ignore TTL" is to make the problem worse by ensuring devices that use Java implement DNS improperly. There is a single TTL used for all DNS entries in the cache. There's some philosophical debate and what led me to the answer in this question which I adapted for the answer.
In terms of Xamarin projects, add this somewhere (I chose early in MainActivity):
Java.Security.Security.SetProperty("networkaddress.cache.ttl", "<integer seconds>");
Replace "<integer seconds>" with your desired TTL for all DNS entries. Be aware lower values might mean you make more DNS queries than you used to, if you're seriously trying to save networking bytes this could be an issue.
I'm leaving Terry Carmen's answer selected as "the answer".

How to make Httpclient fail faster when connecting to an invalid endpoint?

We notice that the .NET HttpClient takes atleast ~20 seconds to fail while trying to connect to an endpoint that is invalid. I was wondering if there is a way to make it fail faster, because our back-end services could be moving to different nodes based on criteria such as load etc. We have a mechanism to retrieve the new location of these services, if there is a communication failure to a particular service. But, since the HttpClient failure time is ~20s, as a result response time for the client request is degrading.
I was looking at the documentation and notice that the HttpClient timeout may take atleast 15s due to the DNS resolution. There was similar post about this here,
HttpClient - how to figure out if server is down faster?
But, all our endpoints have IP addresses in their host that should be preventing the DNS look-up according to this post here,
How to prevent DNS lookup when fetching by using HttpClient
internal static bool TryInternalResolve(string hostName, out IPHostEntry result)
{
if (Logging.On)
Logging.Enter(Logging.Sockets, "DNS", "TryInternalResolve", hostName);
if (string.IsNullOrEmpty(hostName) || hostName.Length > MaxHostName)
{
result = null;
return false;
}
IPAddress address;
if (IPAddress.TryParse(hostName, out address))
{
GlobalLog.Print("Dns::InternalResolveFast() returned address:" + address.ToString());
result = GetUnresolveAnswer(address); // Do not do reverse lookups on IPAddresses.
return true;
}
}
https://referencesource.microsoft.com/#System/net/System/Net/DNS.cs,e177fd4099d6a754,references
We are still trying to capture this behavior in a local environment with fiddler or netmon.
Where could the httpclient be spending bulk of its time to fail?
Are there any master settings that can prevent this time delay on failure?

Exchange Web Services Autodiscover non default link

I am writing a piece of software that runs on a utility device on a customers network, but not on the domain. The autodiscover service is not available off domain the same as it is either on the domain or even on the internet. None of the ways the service works by default will find it according to the docs, but the customer's IT staff tells me, supposedly :/ , it will all work if I can access Autodiscover at the link they gave me. Is there any way to override the default approach and pass it this url to autodiscover from? Hardcoding the link to /exchange.asmx is not an option nor is adding this device to the domain.
I am reusing, and now tweaking, a tried and true piece of software that has been deployed many times, but this situation is a first.
Using the EWS Managed API you may be able to do it using the AutodiscoverService class. It has a constructor that takes the URI of the Autodiscover service as a parameter.
Your code should look something like this. Note that I disable SCP lookup as you are not on a domain. I have not actually tried this code but give it a try:
AutodiscoverService ads = new AutodiscoverService(new Uri("..."));
ads.EnableScpLookup = false;
ads.Credentials = new NetworkCredential(...);
ads.RedirectionUrlValidationCallback = delegate { return true; };
GetUserSettingsResponse grResp = ads.GetUserSettings("someemail#domain.com", UserSettingName.ExternalEwsUrl);
Uri casURI = new Uri(grResp.Settings[UserSettingName.ExternalEwsUrl].ToString());
var service = new ExchangeService()
{
Url = casURI,
Credentials = ads.Credentials,
};

AppFabric - putting fine, getting times out?

After painfully trying to get my virtual environment up and running with Appfabric Caching (1.1), I am able to run 2 nodes into 1 cache cluster.
Both show system up which is good. Before, it was not and was a pain.
So I am now creating a demo app.
The app is being developed on the host computer which can connect to the virtual environment (using VMware and they are all in a domain except the host).
I can put things in the cache and I can see the cache statistics which reflects what I have put in the cache.
But when getting - it fails! It just times out and no idea why or where to go:
? u.Email
"36277#bloggs.com"
? CacheManager.Instance.Cache.GetCacheItem(u.Email)
'CacheManager.Instance.Cache.GetCacheItem(u.Email)' threw an exception of type 'Microsoft.ApplicationServer.Caching.DataCacheException'
base {System.Exception}: {"ErrorCode<ERRCA0018>:SubStatus<ES0001>:The request timed out.. Additional Information : The client was trying to communicate with the server : net.tcp://AppFabricTwo.appfabric.demo.com:22233"}
ErrorCode: 18
HelpLink: "http://go.microsoft.com/fwlink/?LinkId=164049"
Message: "ErrorCode<ERRCA0018>:SubStatus<ES0001>:The request timed out.. Additional Information : The client was trying to communicate with the server : net.tcp://AppFabricTwo.appfabric.demo.com:22233"
SubStatus: -1
TrackingId: {00000000-0000-0000-0000-000000000000}
I have AppFabricOne and AppFabricTwo. I can communicate between them no problems and I can ping and access these 2 from the HOST computer itself (which is hosting the VM's)
Any ideas why this would be and what to do? Windows firewalls on the VM computers are all disabled and these are joined to a domain (And using SQL).
My code:
Adding:
Random r = new Random();
int idChosen = r.Next(1, 99999);
User u = new User { LastName = "Bloggs", FirstName = "Joe", CellPhone = "(555) 555-5555", DOB = DateTime.Today.AddYears(-30), UserID = idChosen, Email = idChosen.ToString() + "#bloggs.com" };
DataCacheItemVersion item = CacheManager.Instance.Cache.Put(u.Email, u, this.txtRegion.Text);
Retrieving:
CacheManager.Instance.Cache.GetCacheItem(u.Email)
yes, I have also tried GetRegionItem but that still gives me the same error as GetCacheItem.
Are you using the same DataCacheFactory object for getting the cache items as the one you are using to put items in the cache ? The fact that PUT works and GET doesn't makes me think that they are different datacachefactory objects somehow.
also are you able to ping to FQDN AppFabricTwo.appfabric.demo from your client machine and is it resolving to correct IP address I.e. Same as appfabrictwo ? Also check telnet to port 22233 is working from your client (if put works this should work anyways though

How to get proxy

I try to get proxy for web request (HttpWebRequest or webclient)
In control panel->Internet Options->Connecitons->LAN Settings
you will see 3 options:
Automatically detect settings
Use automatic configuration script
Use a proxy server for your LAN
I want to make sure no matter whichever setting, my web request pick up the same proxy as browser does.
I am using the code below to achieve this; however, when 1. is checked, I try the same URL in browser and my code, it looks my code is much slower. I guess the way I get proxy in code may be not efficient or appropriate.
Is there anything I can change in my code to mirror the speed of the browser?
var client = (HttpWebRequest)WebRequest.Create(uriStr);
client.Headers["something"] = something;
client.Timeout = ConnectionTimeOut; //1 min
var proxyURI = WebRequest.GetSystemWebProxy().GetProxy(uri);
var proxy = new WebProxy(proxyURI, true)
{
Credentials = CredentialCache.DefaultNetworkCredentials
};
//if there is no proxy, proxy will return the same uri
//do we need check if client.Proxy is null or not,
if (proxyURI != null && !string.IsNullOrEmpty(proxyURI.AbsoluteUri) && !proxy.Address.Equals(uri))
{
client.Proxy = proxy;
}
Your approach is fine.
What may be causing the speed difference is that the browser may have either cached the page you are requesting or cached the proxy/proxy credentials and does not need to perform any net new fetching as you are performing within your code.
Have you tried subsequent requests within your application after acquiring the proxy/credentials?

Categories