Xamarin essentials android -connectivity - c#

I am using XamarinEssential connectivity and I have the following code before running any http call
if(Connectivity.NetworkAccess == NetworkAccess.Internet
|| Connectivity.NetworkAccess == NetworkAccess.ConstrainedInternet)
{
// you can make httpcall
}
else
{
//no connectivity
}
Before making the call I disable the wifi from my Android phone and proceed ,however it still says I have Internet when it shouldn't!!
The only way I can make it work is if I do as follows:
var profiles = Connectivity.Profiles.ToList();
if(Connectivity.NetworkAccess == NetworkAccess.Internet
||Connectivity.NetworkAccess == NetworkAccess.ConstrainedInternet
|| profiles.Contains(ConnectionProfile.WiFi))
{
}
else
{
//no connectivity
}
is the above the correct way to check for connectivity?
It does not seem to work as I expected
many thanks

Related

No Symbols Loaded for Windows.Devices.Radios.dll when trying to swich on Wi-Fi or Bluetooth

I am trying to switch on Bluetooth and Wi-Fi adapter from my C# WPF app
Here's my code:
private async Task<bool> SwitchOnNetworkDevice(RadioKind deviceKind)
{
var radioRequest = await Radio.RequestAccessAsync();
if (radioRequest != RadioAccessStatus.Allowed)
{
return false;
}
var results = await Radio.GetRadiosAsync();
var networkDevice = results.FirstOrDefault(radio => radio.Kind == deviceKind);
if (networkDevice == null)
{
return false;
}
RadioAccessStatus resultsOn;
if (networkDevice.State != RadioState.On)
{
resultsOn = await networkDevice.SetStateAsync(RadioState.On);
}
return true;
}
And I call it like this
await SwitchOnNetworkDevice(RadioKind.WiFi);
I have a problem, though. Before this code worked fine, but now I get this problem (symbols not loaded for Windows.Devices.Radios.dll) after retrieving a list of radios:
It is just visible through debugger, when code is executed, nothing crashes, just networkDevice is always null and nothing gets switched on. How can I fix this?
It was somehow related to the fact that we switched project to 32 bit. When I changed it back to x64, problem went away for some reason, so we left it as x64 only

DNS resolve failing for specific domains. Domains work with nslookup

What I want to happen: Pass the method a domain as a string and have it return true if the domain resolves. False if it does not. The underlying goal is to see if a domain exists.
What happens: Most valid domain strings return true. Some, however, return false despite resolving with nslookup.
I don't understand why certain domains are failing to resolve when they look fine when using command prompt nslookup and nslookup sites. (I've used https://centralops.net/ , http://www.kloth.net/services/nslookup.php , and http://network-tools.com/nslook/)
Method (C#):
//no blank domains
public bool CheckDomain(string sDomain)
{
if (string.IsNullOrWhiteSpace(sDomain)) return false;
for (int i = 1; i <= mQueryRetry; i++)
{
try
{
System.Net.IPAddress dnsCli = System.Net.IPAddress.Parse("8.8.8.8")
DnsClient myClient = new DnsClient(dnsCli);
DnsMessage dnsMessage = myClient.Resolve(ARSoft.Tools.Net.DomainName.Parse(sDomain), RecordType.A);
if ((dnsMessage == null) || ((dnsMessage.ReturnCode != ReturnCode.NoError) && (dnsMessage.ReturnCode != ReturnCode.NxDomain)))
{
throw new Exception("DNS request failed");
}
else
{
foreach (DnsRecordBase dnsRecord in dnsMessage.AnswerRecords)
{
ARecord aRecord = dnsRecord as ARecord;
if (aRecord != null)
{
return true;
}
}
}
}
catch (Exception ex)
{
// Back off and try again after 1 seconds
if (i != mQueryRetry)
{
System.Threading.Thread.Sleep(1000);
}
else
{
System.Diagnostics.Trace.WriteLine(string.Format("Domain: {0} error: {1}", sDomain, ex.Message));
}
}
}
System.Diagnostics.Trace.Flush();
return false;
}
If you plan to test it, I suggest replacing the dnsCli IPAddress with one of these. I've left the IP for the google DNS server in there as an example but I am using my company's DNS server in my production code. I've found that changing the DNS server in no way impacts the method's behavior.
I am using the latest version of Arsoft.Tools.Net (2.2.8) for the DnsClient, DnsMessage, DomainName, DnsRecordBase, and ARecord, classes/objects. We had the same problem with an older version (1.8.1).
Some of the domains that are failing to resolve are:
appraisallinks-amc.com
resurgenstech.com
orpheusvr.com
trovvit.com
Additional info: I've tried some ludicrously long query timeout limits, upwards of 5 minutes, and they made no difference. Therefore, I am certain that this is not a timeout issue.
"you can try and use a different library, the DnsClient (nuget) instead, see dnsclient.michaco.net. The domain names in question seem to work just fine " -
#MichaC
The problem was in fact the Arsoft.Tools.Net library I was using. Switching to DnsClient.Net fixed the problem.

iOS Tracking CLCircularRegion - Heisenbug

One of my iOS applications seems to have the symptoms of a classic Heisenbug. The application tracks a user's home location so certain events happen when the user enters and exits their home location.
While I'm testing the application, it works great. I walk in and out of a CLCircularRegion and it works every which way I try it. It works with the application in the background. It works with the application closed. It works with the application in the foreground. It works with green eggs and ham.
Unfortunately, users are reporting issues where it will be delayed by 15 minutes or so. The users will enter their homes, but the event will not occur until later. In some cases, the event does not occur at all. The pattern seems to be that when the user first starts using the application, it works great. After a day or so, the application doesn't seem to work as well. The events are delayed.
I'll be the first to admit that I'm no expert on the inner workings of CLLocationManager and CLCircularRegion. I believe I have everything set up properly though and I'm having a really hard time trying to figure out how I can debug something like this.
At any rate, I'll show some of my code here. Keep in mind this is developed with Xamarin so it's in C#.
AppDelegate.cs
public static AppDelegate self;
private CLLocationManager locationManager;
private CLCircularRegion[] locationFences;
private void initializeLocationManager()
{
this.locationManager = new CLLocationManager();
// iOS 8 additional permissions requirements
if (UIDevice.CurrentDevice.CheckSystemVersion(8, 0))
{
locationManager.RequestAlwaysAuthorization();
}
locationManager.AuthorizationChanged += (sender, e) =>
{
var status = e.Status;
// Location services was turned off or turned off for this specific application.
if (status == CLAuthorizationStatus.Denied)
{
stopLocationUpdates();
}
else if (status == CLAuthorizationStatus.AuthorizedAlways &&
iOSMethods.getKeyChainBool(OptionsViewController.GENERIC, OptionsViewController.SERVICE_GEOLOCATION_ENABLED))
{
startLocationUpdates();
}
};
if (CLLocationManager.IsMonitoringAvailable(typeof(CLCircularRegion)))
{
locationManager.RegionEntered += (sender, e) =>
{
setRegionStatus(e, "Inside");
};
locationManager.RegionLeft += (sender, e) =>
{
setRegionStatus(e, "Outside");
};
locationManager.DidDetermineState += (sender, e) =>
{
setRegionStatus(e);
};
}
else
{
// cant do it with this device
}
init();
}
public void init()
{
var data = SQL.query<SQLTables.RoomLocationData>("SELECT * FROM RoomLocationData").ToArray();
int dLen = data.Length;
if (dLen > 0)
{
locationFences = new CLCircularRegion[dLen];
for (int x = 0; x < dLen; x++)
{
var d = data[x];
CLCircularRegion locationFence = new CLCircularRegion(new CLLocationCoordinate2D(d.Latitude, d.Longitude), d.Radius, d.SomeID.ToString() + ":" + d.AnotherID.ToString());
locationFence.NotifyOnEntry = true;
locationFence.NotifyOnExit = true;
locationFences[x] = locationFence;
}
}
}
private void setRegionStatus(CLRegionEventArgs e, string status, bool calledFromDidDetermineState = false)
{
string identifier = e.Region.Identifier;
string lastStatus = iOSMethods.getKeyChainItem(OptionsViewController.GENERIC, OptionsViewController.SERVICE_LAST_GEO_STATUS);
if (lastStatus == status + ":" + identifier)
{
return;
}
iOSMethods.setKeychainItem(OptionsViewController.GENERIC, OptionsViewController.SERVICE_LAST_GEO_STATUS, status + ":" + identifier);
string[] split = identifier.Split(new string[] { ":" }, StringSplitOptions.RemoveEmptyEntries);
if (split.Length == 2)
{
try
{
int someID = Convert.ToInt32(split[0]);
int anotherID = Convert.ToInt32(split[1]);
// Notifies our API of a change.
updateGeofenceStatus(someID, anotherID, status);
if (iOSMethods.getKeyChainBool(OptionsViewController.GENERIC, OptionsViewController.SERVICE_GEOLOCATION_NOTIFICATIONS) &&
(status == "Inside" || status == "Outside" || status == "Unknown"))
{
var rm = SQL.query<SQLTables.KeyRoomPropertyData>("SELECT * FROM KeyRoomPropertyData WHERE SomeID ID = ? AND AnotherID = ?",
new object[] { someID, anotherID }).ToArray();
if (rm.Length > 0)
{
if (status == "Unknown")
{
return;
}
var rmD = rm[0];
UILocalNotification notification = new UILocalNotification();
notification.AlertAction = "Geolocation Event";
notification.AlertBody = status == "Inside" ? "Entered " + rmD.SomeName + ": " + rmD.AnotherName :
status == "Outside" ? "Exited " + rmD.SomeName + ": " + rmD.AnotherName :
"Geolocation update failed. If you would like to continue to use Geolocation, please make sure location services are enabled and are allowed for this application.";
notification.SoundName = UILocalNotification.DefaultSoundName;
notification.FireDate = NSDate.Now;
UIApplication.SharedApplication.ScheduleLocalNotification(notification);
}
}
}
catch (Exception er)
{
// conversion failed. we don't have ints for some reason.
}
}
}
private void setRegionStatus(CLRegionStateDeterminedEventArgs e)
{
string state = "";
if (e.State == CLRegionState.Inside)
{
state = "Inside";
}
else if (e.State == CLRegionState.Outside)
{
state = "Outside";
}
else
{
state = "Unknown";
}
CLRegionEventArgs ee = new CLRegionEventArgs(e.Region);
setRegionStatus(ee, state, true);
}
public void startLocationUpdates()
{
if (CLLocationManager.LocationServicesEnabled)
{
init();
if (locationFences != null)
{
foreach (CLCircularRegion location in locationFences)
{
locationManager.StartMonitoring(location);
Timer t = new Timer(new TimerCallback(delegate(object o) { locationManager.RequestState(location); }), null, TimeSpan.FromMilliseconds(500), TimeSpan.FromMilliseconds(-1));
}
}
}
}
public void stopLocationUpdates(bool isRestarting = false)
{
if (locationFences != null)
{
foreach (CLCircularRegion location in locationFences)
{
locationManager.StopMonitoring(location);
}
}
if (!isRestarting)
{
var rooms = SQL.query<SQLTables.KeyRoomPropertyData>("SELECT * FROM KeyRoomPropertyData").ToArray();
foreach (SQLTables.KeyRoomPropertyData room in rooms)
{
// notifies our API of a change
updateGeofenceStatus(room.SomeID, room.AnotherID, "Unknown");
}
}
}
I know it's a lot of code for anyone to sift through, but I really have no good theory at this point as to what is causing this bug or if it is even possible to fix with the limitations of iOS.
A few theories that I have are if the CLLocationManager.PausesLocationUpdatesAutomatically property may have something to do with it, or some other property of CLLocationManager such as ActivityType, DesiredAccuracy, or DistanceFilter. I've left all of these at their defaults which I would assume would be fine, but I'm not really sure.
Another theory is that there is an uncaught exception being thrown some time after the "service" has been running in the background for some time. If that is the case, is there anything iOS does that would give me a stack trace or something? In all of my tests, I never ran across any exceptions being thrown from this code so I kind of doubt that's the issue. At this point though, I'm willing to entertain any ideas or suggestions.
Also, please keep in mind that in order for this application to work the way it was intended, the location update events MUST occur as soon as the user enters or exist the CLCircularRegion (within a minute or so at least). Obviously I have to leave it to the user to keep their location services enabled and allow the app to have the appropriate permissions.
You are most likely right on target with your diagnosis - it is classic observer effect.
When you test the app, when users play with a new app, the iphone is being actively used. It is not given a chance to fall asleep. What happens on a next day, when users return home - their phones most likely are not in use for extended time right before reaching home location: normally we do not use phones during "last mile" walk after leaving public transportation, or while driving back home. iOS notices this extended inactivity period and adjusts its own behavior to optimize battery life.
The easiest way to observe this is to put together a simple breadcrumbs app - set geofence at your location and keep doing that every time you get exit event. Depending on the way you use (or not use) your phone results will be very different while walking the same route.
And when you get home, the phone is usually the last thing you reach for as well.
You may want to ask users to give more details on how exactly they used phones last 15 minutes before and after entering home, what other apps they use, if they drive do they keep turn by turn navigation app running etc. You will spot the pattern.
re. Also, please keep in mind that in order for this application to
work the way it was intended, the location update events MUST occur as
soon as the user enters or exist the CLCircularRegion (within a minute
or so at least).
You can't do this with geofencing only, especially taking into account different arrival/departure patterns - walking vs driving, "descend" paths (e.g. arrivals with U-turns). You have to anticipate both delays longer than 1 minute and "premature" triggering. I am afraid there is no workaround.
Some things to check:
What are some typical values for radius? You may want to consider reducing that.
iOS Location Services will provide a quicker response if the device has WiFi enabled even if the user is not connected to a network. Check if the problem users have wifi disabled and if you haven't done so already maybe test your device w/o wifi.
Is there a delay in the notification? That is, does the region event occur correctly but for some reason there is a delay in the notification?
How many RoomLocationData entries are there? iOS limits each app to 20 regions max.
Presuming the users are driving to/from their house, you may want to try the following settings (code is Swift):
locationManager.distanceFilter = kCLDistanceFilterNone
locationManager.desiredAccuracy = kCLLocationAccuracyBest // or kCLLocationAccuracyBestForNavigation
locationManager.pausesLocationUpdatesAutomatically = true // try false if nothing else works
locationManager.allowsBackgroundLocationUpdates = true
locationManager.activityType = CLActivityType.AutomotiveNavigation

Check for internet connectivity from Unity

I have a Unity project which I build for Android and iOS platforms. I want to check for internet connectivity on Desktop, Android, and iOS devices. I've read about three different solutions:
Ping something (for example Google) - I totally dislike such decision, and I've read about mistakes on Android.
Application.internetReachability - According to Unity's documentation, this function will only determine that I have a POSSIBILITY of connecting to the Internet (it doesn't guarantee a real connection).
Network.TestConnection() - If I have no Internet connection, my application fails. So this isn't correct either.
How can I determine whether I have internet connectivity from within Unity?
I don't actually believe that Network.TestConnection() is the right tool for this job. According to the documentation, it looks to me like it's meant for testing if NAT is working and your client is publicly reachable by IP, but what you want to check for is whether you have general internet connectivity.
Here is a solution that I found on Unity Answers by user pixel_fiend, which simply tests a website to see if the user has connectivity. One benefit of this code is that it uses IEnumerator for asynchronous operation, so the connectivity test won't hold up the rest of your application:
IEnumerator checkInternetConnection(Action<bool> action){
WWW www = new WWW("http://google.com");
yield return www;
if (www.error != null) {
action (false);
} else {
action (true);
}
}
void Start(){
StartCoroutine(checkInternetConnection((isConnected)=>{
// handle connection status here
}));
}
You can change the website to whatever you want, or even modify the code to return success if any one of a number of sites are reachable. AFAIK there is no way to check for true internet connectivity without trying to connect to a specific site on the internet, so "pinging" one or more websites like this is likely to be your best bet at determining connectivity.
public static IEnumerator CheckInternetConnection(Action<bool> syncResult)
{
const string echoServer = "http://google.com";
bool result;
using (var request = UnityWebRequest.Head(echoServer))
{
request.timeout = 5;
yield return request.SendWebRequest();
result = !request.isNetworkError && !request.isHttpError && request.responseCode == 200;
}
syncResult(result);
}
void Start()
{
StartCoroutine(CheckInternetConnection(isConnected =>
{
if (isConnected)
{
Debug.Log("Internet Available!");
}
else
{
Debug.Log("Internet Not Available");
}
}));
}
IEnumerator CheckInternetConnection(Action<bool> action)
{
UnityWebRequest request = new UnityWebRequest("http://google.com");
yield return request.SendWebRequest();
if (request.error != null) {
Debug.Log ("Error");
action (false);
} else{
Debug.Log ("Success");
action (true);
}
}
Since WWW has deprecated, UnityWebRequest can be used instead.
i know this is old, but maybe can help you.
public bool CheckInternetConnection(){
return !(Application.internetReachability == NetworkReachability.NotReachable)
}
Ping 8.8.8.8 instead of sending a GET
unity already provides the tool for that:
Ping
The ping operation is asynchronous and a ping object can be polled for
status using Ping.isDone. When a response is received it is in
Ping.time.
Windows Store Apps: A stream socket is used to mimic ping
functionality, it will try to open a connection to specified IP
address using port 80. For this to work correctly, InternetClient
capability must be enabled in Package.appxmanifest.
Android: ICMP sockets are used for ping operation if they're
available, otherwise Unity spawns a child process /system/bin/ping for
ping operations. To check if ICMP sockets are available, you need to
read the contents for /proc/sys/net/ipv4/ping_group_range. If ICMP
sockets are available, this file should contain an entry for 0
2147483647.
using UnityEngine;
using System.Collections.Generic;
public class PingExample : MonoBehaviour
{
bool isConnected = false;
private IEnumerator Start()
{
while(true)
{
var ping = new Ping("8.8.8.8");
yield return new WaitForSeconds(1f);
while (!ping.isDone)
{
isConnected = false;
yield return null;
}
isConnected = true;
Debug.Log(ping.time);
}
}
}
I've created an Android's library that can be used as Unity's plugin for this purpose. If anyone's interested it's available under https://github.com/rixment/awu-plugin
As for the iOS version unfortunately I don't have enough of knowledge in this area. It would be nice if someone could extend the repo to include the iOS version too.
With the latest version of Unity, WWW has become obsolete, hence you need to use WebRequest.
This is the bit of codes I'm using to check if the user is online:
private string HtmlLookUpResult_Content;
private char[] HtmlLookUpResult_Chars;
private StreamReader HtmlLookUpResult_Reader;
private bool HtmlLookUpResult_isSuccess;
private HttpWebRequest HtmlLookUpResult_Request;
private HttpWebResponse HtmlLookUpResult_Response;
public bool CheckIfOnline()
{
HtmlLookUpResult_Content = UniversalEnum.String_Empty;
HtmlLookUpResult_Request = (HttpWebRequest)WebRequest.Create(UniversalEnum.WebHtml_isOnline);
HtmlLookUpResult_Request.Timeout = 5000;
try
{
using (HtmlLookUpResult_Response = (HttpWebResponse)HtmlLookUpResult_Request.GetResponse())
{
HtmlLookUpResult_isSuccess = (int)HtmlLookUpResult_Response.StatusCode < 299 && (int)HtmlLookUpResult_Response.StatusCode >= 200;
if (HtmlLookUpResult_isSuccess)
{
using (HtmlLookUpResult_Reader = new StreamReader(HtmlLookUpResult_Response.GetResponseStream()))
{
HtmlLookUpResult_Chars = new char[1];
HtmlLookUpResult_Reader.Read(HtmlLookUpResult_Chars, 0, 1);
HtmlLookUpResult_Content += HtmlLookUpResult_Chars[0];
}
}
}
}
catch
{
HtmlLookUpResult_Content = UniversalEnum.String_Empty;
}
if (HtmlLookUpResult_Content != UniversalEnum.String_Empty)
{
return true;
}
else
{
return false;
}
}
If you would like to know if the user is just online, you can get the result just from the boolean HtmlLookUpResult_isSuccess in the code. But, in reality, you most likely want to confirm the user has also access to your server or whatever remote system you use in your project, right? Which is what the remaining of the code does.
In case you wonder what UniversalEnum is, in my code, it's a separate non-Monobehavior script that contains all persistent variables (like strings and hashes) I'm planning on reusing in my project. For short:
UniversalEnum.String_Empty = "";
UniversalEnum.WebHtml_isOnline = "http://www.ENTER_YOUR_WEBSITE_HERE.com/games-latestnews/isOnline.html"
That isOnline.html file is, as you can see, a file in the folder "games-latestnews" in the HTML_content of my hosted website and it contains only [1] as it content. It has no header, no actual content and is pretty much like a .txt file set online. I'm using this method also because I can add new news to my game by just adding new HTML page in that folder. I'm also surrounding the content check with a Try{} so that if ANYTHING fails, it returns the Catch{} value and then by comparing if the content (a string) is an empty string or contain anything, we know if the user is both online and if he/she has access to your website.
On good example of why you would want to check that the user has both access to the net AND to your website is if the user is using a limited network such as what you might find at a school. If a school decided to ban your website due to whatever reason, just looking up if the connection is possible will return a false positive since it wouldn't access the actual webpage anyway.
You can check network connection using this code
if(Application.internetReachability == NetworkReachability.NotReachable){
Debug.Log("Error. Check internet connection!");
}

SQL Server service does not start by code

I need a service that run automatically start the SQL instances that are on the machine. So far so good, I can make all of them work, but when I run on a machine with Windows 7 I get an error 1053 (timeout). But changed the timeout to 180000 and the error continues.
I do the same process in Windows 10 and runs 100% on instances of SQL Express 2005, 2008 and 2012.
I can not be sure if the problem is actually Windows 7 or SQL Server 2005 that is in this windows 7 if I do the process manually start it starts normally.
Code:
public static bool StartServices()
{
try
{
bool startedWithSuccess = false;
foreach (var servico in GetInstances())
{
using (servico)
{
if (servico.Status != ServiceControllerStatus.Running
&& servico.Status != ServiceControllerStatus.StartPending)
{
servico.Start();
startedWithSuccess = TimeoutHelper.RetryUntilSuccessOrTimeout(() =>
{
servico.Refresh();
return servico.Status != ServiceControllerStatus.Running ? false : true;
}, TIMEOUT_IN_MILLISECONS);
}
else
{
startedWithSuccess = true;
}
}
}
return startedWithSuccess;
}
catch (Exception)
{
throw new SqlServerStartServiceException();
}
}
public static ServiceController[] GetInstances()
{
ServiceController[] services = ServiceController.GetServices().Where(x => x.ServiceName.Contains("SQL")).ToArray();
var lista = services.Where(x => x.DisplayName.Contains("Agent") ||
x.DisplayName.Contains("Browser") ||
x.DisplayName.Contains("VSS") ||
x.DisplayName.Contains("Active")).ToArray();
return services.Except(lista).ToArray();
}
Using the cmd and net start xxxx command also works.
The mcs will run as you user that's not the same thing as the user this service runs as. Navigate to the service right click> properties and change the user from local machine to one that has access. Try your user to see if that works than its a security issue. technet
I solved this problem inserting dependencies in the service.
this.serviceInstaller.ServicesDependedOn = SqlServerServiceHelper.GetInstances().Select(x => x.ServiceName).ToArray();
public static ServiceController[] GetInstances()
{
ServiceController[] services = ServiceController.GetServices().Where(x => x.ServiceName.Contains("SQL")).ToArray();
var servicesToRemove = services.Where(x => x.DisplayName.Contains("Agent") ||
x.DisplayName.Contains("Browser") ||
x.DisplayName.Contains("VSS") ||
x.DisplayName.Contains("Active")).ToArray();
return services.Except(servicesToRemove).ToArray();
}

Categories

Resources