How to force XAMARIN app to use WIFI only - c#

I am building an app in XAMARIN, that has to connect to a custom device via wifi and that device does not have internet connection. So my app always wants to work on mobile data and there for never communicating with the device. Is there anyway to force the app to use only WIFI and never mobile data? I guess I'm not the only one with that problem as I've seen a few posts about this, but none in xamarin specific.
EDIT:
I found that if I let the application run for about 50 seconds, then it will use the wifi insted of mobile data. Is this due to some timeout? If so, then can I shorten the timeout?

After a lot of sweating I have found the solution. Make a class with this code:
using Android.Content;
using Android.Net;
namespace Project.Communication
{
class ForceNetworkType
{
public static Context _context = Android.App.Application.Context;
/// <summary>
/// Forces the wifi over cellular
/// </summary>
public static void ForceWifiOverCellular()
{
ConnectivityManager connection_manager = (ConnectivityManager)_context.GetSystemService(Context.ConnectivityService);
NetworkRequest.Builder request = new NetworkRequest.Builder();
request.AddTransportType(TransportType.Wifi);
var callback = new ConnectivityManager.NetworkCallback();
connection_manager.RegisterNetworkCallback(request.Build(), new CustomNetworkAvailableCallBack());
}
/// <summary>
/// Forces the cellular over wifi.
/// </summary>
public static void ForceCellularOverWifi()
{
ConnectivityManager connection_manager = (ConnectivityManager)_context.GetSystemService(Context.ConnectivityService);
NetworkRequest.Builder request = new NetworkRequest.Builder();
request.AddTransportType(TransportType.Cellular);
connection_manager.RegisterNetworkCallback(request.Build(), new CustomNetworkAvailableCallBack());
}
}
/// <summary>
/// Custom network available call back.
/// </summary>
public class CustomNetworkAvailableCallBack : ConnectivityManager.NetworkCallback
{
public static Context _context = Android.App.Application.Context;
ConnectivityManager connection_manager = (ConnectivityManager)_context.GetSystemService(Context.ConnectivityService);
public override void OnAvailable(Network network)
{
//ConnectivityManager.SetProcessDefaultNetwork(network); //deprecated (but works even in Android P)
connection_manager.BindProcessToNetwork(network); //this works in Android P
}
}
}
And Then you just use where you need to force certain Network:
ForceNetworkType.ForceWifiOverCellular();
to force the wifi over mobile data.

Using Xamarin.Essentials.
Like this:
>
var profiles = Connectivity.ConnectionProfiles;
if (profiles.Contains(ConnectionProfile.WiFi))
{
// Active Wi-Fi connection.
}
You can change this check to block users that without a wifi connection.
reference:
https://learn.microsoft.com/en-us/dotnet/api/xamarin.essentials.connectionprofile?view=xamarin-essentials

I believe the best you can actually do is set the preference of what you want the device to use. With both OS, it will prefer a Wifi connection over a cellular connection unless it times out on the request.
However you can use the Reachability class in iOS to say something like:
//PseudoCode
if(ReachabilityStatus == ReachableViaWifi)
{
//Only do things when WIFI is on
}
else
{
//Only do things when WIFI is not on
}
Within Android, you can do the following with ConnectivityManager:
//PseudoCode again
ConnectivityManager connectivityManager = (ConnectivityManager)GetSystemService(Context.ConnectivityService);
NetworkInfo wifi = connectivityManager.GetNetworkInfo(ConnectivityType.Wifi);
if (wifi.IsConnected)
{
//Pretty fly for a wifi
}
else
{
//No wifi here!
}

Related

How to register event handler safe in c#?

Im am working an bluetooth low energy desktop windows application for a custom bluetooth service. The device sending the data was tested with Android applications. Now I am working on a windows library in C# to receive messages from the device. The service on the Microcontroller is based on the Atmel CSC service. The microcontroller uses the notification service to establish a serial chat between Client and Server.
My application always crashes with exit code -1073740791 (0xc0000409). This exit code is caused by a stack overrun (STATUS_STACK_BUFFER_OVERRUN (0xc0000409)). This is related to a /gs exception. The application receives data for several seconds before it crashes (~5-30seconds?).
This issue occurs when I am registering an event handler for the Bluetooth GATT notify service.
characteristic.ValueChanged += CharacteristicValueChangedRequested;
The event handler looks like:
private void CharacteristicValueChangedRequested(GattCharacteristic sender, GattValueChangedEventArgs args)
{
//GattNotifyCharacteristic_sender.ValueChanged -= CharacteristicValueChangedRequested_Async;
if (args.CharacteristicValue != null)
{
var length = args.CharacteristicValue.Length;
if (length > 0)
{
if (length < 120)
{
var reader = DataReader.FromBuffer(args.CharacteristicValue);
LatestClientMessage = reader.ReadString(length);
ClientMessages.Add(LatestClientMessage);
}
}
}
//GattNotifyCharacteristic_sender.ValueChanged += CharacteristicValueChangedRequested_Async;
}
If I do not register the event handler for received messages the application is stable. If I register an empty event handler with no code the application also crashes with the same exit code. I'll try to receive about 100 notifications per second. The application is a bit more stable if I ll try to receive fewer data.
I ll tried different methods to register an event handler, but I think somehow I need to manage the same event handler being called multiple times.
I also tried to unregister the event handler immediately when called and reregister when finished, but that does not help a lot.
The characteristic is of type GattCharacteristic
GattCharacteristic
using Windows.Devices.Bluetooth.GenericAttributeProfile;
The registration for the notify service is done by the following code:
/// <summary>
/// Register for Notification at BLE Device
/// </summary>
/// <param name="address"></param>
/// <param name="Msg"></param>
public async Task<string> RegisterNotificationForced_Async(ulong address)
{
var device = await BluetoothLEDevice.FromBluetoothAddressAsync(address);
var mGattDeviceServicesResult = await device.GetGattServicesAsync();
GattCommunicationStatus result = GattCommunicationStatus.Unreachable;
foreach (var service in mGattDeviceServicesResult.Services)
{
if (service.Uuid == mGuid) //Atmel CSC Service
{
var mGattCharacteristicsResult = await service.GetCharacteristicsAsync(); //Characteristic on BLE Device
if (mGattCharacteristicsResult.Status == GattCommunicationStatus.Success)
{
var characteristics = mGattCharacteristicsResult.Characteristics;
foreach (var characteristic in characteristics)
{
if (characteristic.CharacteristicProperties.HasFlag(GattCharacteristicProperties.Notify))
{
characteristic.ValueChanged += CharacteristicValueChangedRequested;
GattClientCharacteristicConfigurationDescriptorValue DescriptorVal;
DescriptorVal = GattClientCharacteristicConfigurationDescriptorValue.Notify;
result = await characteristic.WriteClientCharacteristicConfigurationDescriptorAsync(DescriptorVal);
if (result != GattCommunicationStatus.Success)
{
throw new System.ArgumentException("Failed to register notification at BLE Device");
}
}
}
}
else
{
throw new System.ArgumentException("Characteristics on BLE device not found");
}
}
}
return $"{result}";
}
The problem might be related to the windows bluetooth driver and the event handler registered there....
Thank you for your comments...
I was not able to really find the issue related to the problem. The problem does not exist when using the nuget package microsoft.netcore.universalwindowsplatform. At least I found a workaround. Before I was using Microsoft.Windows.SDK Contracts. The new code is based on the following example:
https://learn.microsoft.com/en-us/samples/microsoft/windows-universal-samples/bluetoothle/

Redis Cache Number of connected clients increasing

I am developing a microservice architecture application where I am using a Redis Cache to cache frequently used information. The issue is that the number of connected clients is constantly increasing and I don't know why.
I am accessing the Redis Cache from an ASP.NET Web API and a Web Job. The NuGet package used for connection is "StackExchange.Redis" (https://github.com/StackExchange/StackExchange.Redis).
The way I am connecting to Redis in code is as follows:
connection = ConnectionMultiplexer.Connect(configurationOptions);
connection.ConnectionFailed += ConnectionFailed;
connection.ConnectionRestored += ConnectionRestored;
connection.InternalError += InternalError;
if (!connection.IsConnected)
{
//_traceSource.TraceWarning($"Connection to REDIS '{_endpointAddress}' was not established.");
}
database = connection.GetDatabase();
return database;
In addition, I have implemented the Dispose() method to make sure that connections are disconnected properly:
public void Dispose()
{
connection?.Close(true);
}
Implement a static Helper class like this.
/// <summary>
/// Helper class for connection with Redis Server.
/// </summary>
public static class Helper
{
/// <summary>
/// Configuration option to connect with Redis Database.
/// </summary>
private static Lazy<ConfigurationOptions> configOptions = new Lazy<ConfigurationOptions>(() =>
{
var configOptions = new ConfigurationOptions();
configOptions.EndPoints.Add("Your Redis sever name");
configOptions.AbortOnConnectFail = false;
configOptions.AllowAdmin = true;
configOptions.KeepAlive = 4;
configOptions.Password = "Redis server password";
return configOptions;
});
private static Lazy<ConnectionMultiplexer> lazyConnection = new Lazy<ConnectionMultiplexer>(() => ConnectionMultiplexer.Connect(configOptions.Value));
/// <summary>
/// Connection property to connect Redis Database.
/// </summary>
public static ConnectionMultiplexer Connection
{
get
{
return lazyConnection.Value;
}
}
}
After that use it like this wherever you need it.
var RedisDatabase = Helper.Connection.GetDatabase(Database Number);
This will maintain the connections automatically. Hope this will help.
I'd take the following 3 steps :
Add shutdown hook which calls connection.close().
Refer : How to call event before Environment.Exit()?
But it's not guaranteed to be called always. Hence, #2:
Configure Redis with client timeout to close connections idle > some threshold
https://redis.io/topics/clients
Ensure duplicate connections aren't created unnecessarily. Ex: a new connection is created per call to Redis. #Keyur Ramoliya 's answer seems to address this.

C# - Arduino Serial Communication freezes(?) while reading Data

My program checks on startup if an Arduino is connected, and if that's the case, it sends a test message via Serial Port to see if it responds correctly. It then waits for the result, and if the answer is "success", it continues starting up.
Here's the important part of the code:
...
using System.IO.Ports;
using System.Threading;
namespace ProFlagControlApp
{
public partial class MainWindow : Window
{
static AutoResetEvent autoEvent = new AutoResetEvent(false);
...
private SerialPort arduinoBoard = new SerialPort();
private string ardAnswer;
/// <summary>
/// Automatically detect the COM port on which an Arduino is connected.
/// </summary>
/// <returns>If an Aduino is connected, the port is returned as a string. If not, it returns null.</returns>
private string AutodetectArduinoPort() { ... }
/// <summary>
/// Initializing communications with the Arduino.
/// </summary>
/// <param name="port">The identifier of the port the Arduino is connected to. Example: 'COM4'</param>
private void OpenArduinoConnection(string port)
{
if (!arduinoBoard.IsOpen)
{
arduinoBoard.DataReceived += new SerialDataReceivedEventHandler(ArdSerPort_DataReceived);
arduinoBoard.BaudRate = 115200;
arduinoBoard.PortName = port;
arduinoBoard.Parity = Parity.None;
arduinoBoard.DataBits = 8;
arduinoBoard.StopBits = StopBits.One;
arduinoBoard.Handshake = Handshake.None;
arduinoBoard.Open();
}
else
{
throw new InvalidOperationException("port is already in use");
}
}
/// <summary>
/// The event handler for receiving data from the Arduino.
/// </summary>
private void ArdSerPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
string data = arduinoBoard.ReadTo("\x03"); // Read Arduino data until exit code
ardAnswer = data.Split('\x02', '\x03')[1]; // Only save information between the start and exit code
autoEvent.Set();
}
public MainWindow()
{
InitializeComponent();
...
// Detect if Arduino is connected, shutdown the application otherwise.
if (AutodetectArduinoPort() == null) { ... }
OpenArduinoConnection(AutodetectArduinoPort());
// Test Arduino communication
arduinoBoard.Write("connection#");
autoEvent.WaitOne(500);
if (ardAnswer != "success")
{
MessageBox.Show("Error communicating with Arduino", "Control Unit Error", MessageBoxButton.OK, MessageBoxImage.Warning);
Application.Current.Shutdown();
return;
}
...
}
...
}
}
I checked via the Arduino Serial Monitor if the command is read correctly and the appropriate response message is written into the Serial Port, which is the case.
However, the ArdSerPort_DataReceived event is never triggered. When I try to manually put a ardAnswer = arduinoBoard.ReadTo("\x03"); before it tests what is in the ardAnswer variable, the program seems to freeze and does not continue with anything.
I am really wondering why. I have to admit that I haven't touched this program for quite a while now, but when I last worked on it, it all behaved as it should, with the exact same code.
You most likely have a race condition: when you open the serial port (on most systems), the change in the DTR/RTS serial port signals will reset the Arduino. That, in turn, will cause the bootloader to run, wait for a short period to see if there's any code to load. If not, it drops into your program.
My guess: you are sending your test command while the bootloader is waiting, causing some or all of your command to get lost.
Try: adding a delay (few seconds to start) after you open the port and before you send your command.
Even better: have your Arduino code send a response or print a banner of some sort when it first starts. Then, have your C# code wait for that after opening the serial port, so you know that the Arduino has reset, gone through the bootloader, and your code is now fully up and running.
I got the answer. C# / Visual Studio / .NET Framework / Whatsoever doesn't seem to like high baud rates. I turned it down from 115200 to 9600 (standard as far as I know), and now everything works as it should. Strange.

testing internet connection on a cellular network

I have an application that was written for remote trucks to use on cell service. Before I do anything, I am checking the internet with this class:
using System.Net;
namespace SSS.ServicesConfig.MiscClasses
{
public class VerifyInternetAccess
{
public static bool HasInternet()
{
try
{
using (var client = new WebClient())
using (var stream = client.OpenRead("http://www.google.com"))
{
return true;
}
}
catch
{
return false;
}
}
}
}
In some cases, the light on the external cellular device has a green light as if it has internet. My test class comes back false so it thinks it does not have internet.
The driver can then open up internet explorer, close internet explorer, promptly run my application and it passes the test above.
The users are saying that IE is 'waking up' the internet so that it can transfer.
Doesn't my class do essentially the same thing? If not, how can I 'wake up' the internet connection as IE does?
You didn't state if you're restricted to a certain mobile OS but this works on a normal box.
I try to leverage two features of the System.Net.NetworkInformation namespace.
I start with registering for the NetworkChangedEvent. By calling GetIsNetworkAvailable you get an idea if there is at least one other NIC present that is not the loopback interface.
If there is no connection I try to wake-up the network layer by getting pinging a host.
I use the Dns.GetHostEntry to obtain all IP Adresses known for a host. Next I try to Ping the address one by one.
Be aware that not all hosts allow ICMP traffic which would lead to timeouts in all circumstances. If however in the meantime the network becomes available the NetworkChanged event should have been fired and set the HasConnection to true
public class VerifyInternetAccess
{
private static bool HasConnection = false;
static VerifyInternetAccess()
{
NetworkChange.NetworkAvailabilityChanged += (o, ca) =>
{
HasConnection = ca.IsAvailable;
};
HasConnection = NetworkInterface.GetIsNetworkAvailable();
}
public static bool HasInternet()
{
bool hasEnded = false;
if (!HasConnection)
{
// let's try to wake up...
using (var ping = new Ping())
{
var iphost = Dns.GetHostEntry("www.google.com");
foreach (var addr in iphost.AddressList)
{
var reply = ping.Send(addr);
if (reply.Status == IPStatus.Success)
{
HasConnection = true;
break;
}
}
}
}
return HasConnection;
}
}

Enable or disable certain IPs from accessing my WCF service

I'm looking for a way to enable or disable certain IPs from accessing and adding my WCF service as service reference.
Currently it's possible to add our Webservice publicly, how can I add an IP filter?
Or is there any other setting I could use?
I've seen Can I setup an IP filter for a WCF Service? about adding <IPFilter /> to web.config, but the essential part in code is missing thus unusable.
Note; The webservices are part of a bigger project and cannot be separated as individual project which is available via HTTPS (a website).
Since I don't think there is an automatic way to do it in WCF, you have two main options:
If you want something secured, don't want to implement anything but your environment uses firewalls, you can configure the firewall in order to refuse the connections coming from specific IP addresses.
Otherwise, you can implement an IP filter as in the article you mentionned (i.e. as a serviceBeharvior, not described here) or simpler as a single private method called by all your public webservice methods that throw an error code if the IP of the client is not allowed (based on white or black lists of IPs in a file or a database).
/// <summary>
/// Get the client IP address.
/// </summary>
private string GetClientIpAddress()
{
string result = string.Empty;
try
{
OperationContext context = OperationContext.Current;
MessageProperties messageProperties = context.IncomingMessageProperties;
RemoteEndpointMessageProperty endpointProperty = messageProperties[RemoteEndpointMessageProperty.Name] as RemoteEndpointMessageProperty;
result = endpointProperty.Address;
}
catch (Exception ex)
{
logger.Error(ex);
}
return result;
}
/// <summary>
/// Returns <code>true</code> if the current IP address is allowed
/// to access the webservice method, <code>false</code> otherwise.
/// </summary>
private bool CheckIPAccessRestriction()
{
bool result = false;
List<string> allowed = GetAllowedIpAddressesList();
if (allowed.Count() == 0)
{
result = true;
}
else
{
var ip = GetClientIpAddress();
result = allowed.Contains(ip);
}
return result;
}
If you Web service is hosted in IIS you can restrict IP addresses there:

Categories

Resources