Using: Windows 10, C# .NET 2015 Community, UWP
Im trying to build a windows-universal-app that pairs my PC with a BLE device.
Whats already working is enumerating nearby devices, pair with a selected one and getting information like battery-level and firmware-revision.
The problem now is that when I try to get a custom service, my task ends because of an "System.Exception" at .GetGattService
System.Exception.Message: "Element not found. (Exception from HRESULT: 0x80070490)"
System.Exception.Stack : "at Windows.Devices.Bluetooth.BluetoothLEDevice.GetGattService(Guid serviceUuid)\r\n at SettingsCs.Settings.d__23.MoveNext()"
This is the code that's not working:
private async Task<SettingsReturn> writeSettingTransition(BluetoothLEDevice device, byte[] byteSettings)
{
//Check if device is available
if (device != null)
{
Guid SERVICE_CUSTOM = new Guid("7e0bc6be-8271-4f5a-a126-c24220e6250c");
GattDeviceService service = device.GetGattService(SERVICE_CUSTOM);
//Check if service is available
if (service == null)
{
return SettingsReturn.INIT_ERROR;
}
GattCharacteristic characteristic = service.GetCharacteristics(BLETestApp.CHAR_SETTINGS)[0];
//Check if characteristic is available
if (characteristic == null)
{
return SettingsReturn.INIT_ERROR;
}
var writer = new DataWriter();
writer.WriteBytes(byteSettings);
var buffer = writer.DetachBuffer();
await characteristic.WriteValueAsync(buffer);//********
bool success = characteristic.CharacteristicProperties.HasFlag(GattCharacteristicProperties.Write);
if (success == true)
{
// Take care of the 8 bit byte for the counter (max = 255 (unsigned))
if (TRANSACTION_ID > 250)
{
TRANSACTION_ID = 0;
}
else
{
// Count TANSACTION_ID one up
TRANSACTION_ID++;
}
return SettingsReturn.OK;
}
else
{
return SettingsReturn.WRITE_ERROR;
}
}
else
{
return SettingsReturn.INIT_ERROR;
}
}
I hope somenone can help me or tell me what I'm doing wrong.
I can't pinpoint the error you get, use the debugger to check if your characteristic has write permission.
I have changed your code in a way I write to my device successfully.
Also added a try catch block.
Here it is:
private async Task<SettingsReturn> writeSettingTransition(BluetoothLEDevice device, byte[] byteSettings)
{
bool success = false;
//Check if device is available
if (device != null)
{
Guid SERVICE_CUSTOM = new Guid("7e0bc6be-8271-4f5a-a126-c24220e6250c");
GattDeviceService service = device.GetGattService(SERVICE_CUSTOM);
//Check if service is available
if (service == null)
{
return SettingsReturn.INIT_ERROR;
}
GattCharacteristic characteristic = service.GetCharacteristics(BLETestApp.CHAR_SETTINGS)[0];
//Check if characteristic is available
if (characteristic == null)
{
return SettingsReturn.INIT_ERROR;
}
IBuffer writeBuffer = byteSettings.AsBuffer();// using Windows.Storage.Streams
try
{
// BT_Code: Writes the value from the buffer to the characteristic.
var result = await characteristic.WriteValueAsync(writeBuffer);
if (result == GattCommunicationStatus.Success)
{
// NotifyUser("Successfully wrote value to device" );
success = true;
}
else
{
// NotifyUser($"Write failed: {result}");
success = false;
}
}
catch (Exception ex) when ((uint)ex.HResult == 0x80650003 || (uint)ex.HResult == 0x80070005)
{
// E_BLUETOOTH_ATT_WRITE_NOT_PERMITTED or E_ACCESSDENIED
// This usually happens when a device reports that it support writing, but it actually doesn't.
// NotifyUser(ex.Message, NotifyType.ErrorMessage);
}
if (success)
{
// Take care of the 8 bit byte for the counter (max = 255 (unsigned))
if (TRANSACTION_ID > 250)
{
TRANSACTION_ID = 0;
}
else
{
// Count TANSACTION_ID one up
TRANSACTION_ID++;
}
return SettingsReturn.OK;
}
else
{
return SettingsReturn.WRITE_ERROR;
}
}
else
{
return SettingsReturn.INIT_ERROR;
}
}
There can be typos and other mishaps, hope it helps.
Related
I need your help guys in order to fix issue with non closing TCP connection.
Basically it works fine but after a few minutes it stucks with connection in CLOSE_WAIT state.
The logic of the code:
The code accepts first packet and parse it and after that it sends the CRC back to the client. If the CRC valid then client sends the main packet to the server and repeat it. Once if there are no packets then client close connection but sometimes it does not. In this case server (code below) close connection after 1 minute of the communications.
I assume it should correspond to https://www.googlecloudcommunity.com/gc/Cloud-Product-Articles/TCP-states-explained/ta-p/78462 as well
Here is C# code
void TCPListenerServer(object obj) {
CancellationToken token = (CancellationToken) obj;
if (token.IsCancellationRequested) {
isDisposed = true;
if (listener != null) {
listener.Stop();
}
return;
} else {
try {
isDisposed = false;
try {
var validIP = IPAddress.Parse(Properties.Settings.Default.ServerIP);
listener = new TcpListener(validIP, Properties.Settings.Default.ServerPort);
listener.Start();
while (isDisposed == false || token.IsCancellationRequested == false) {
if (token.IsCancellationRequested || isDisposed) {
break;
} else {
if (!listener.Pending()) {
Thread.Sleep(50);
continue;
}
listener.Server.ReceiveTimeout = 10000;
listener.Server.LingerState = new LingerOption(true, 0);
var client = listener.AcceptTcpClient();
var arrThread = new ThreadParams() {
Client = client, Token = m_Cts.Token
};
var t = new Thread(ProcessClientRequests) {
IsBackground = true,
Name = "ClientConnectionThread",
};
clientThreads.Add(t);
t.Start((object) arrThread);
}
}
} catch (SocketException ex) {
if (ex.SocketErrorCode == SocketError.Interrupted) {}
} catch (Exception ex) {} finally {
if (listener != null) {
listener.Server.Close();
listener.Stop();
}
}
} catch (Exception ex) {
}
}
}
private void ProcessClientRequests(object argument) {
TcpClient client = ((ThreadParams) argument).Client;
CancellationToken token = ((ThreadParams) argument).Token;
client.SendTimeout = 10000;
client.ReceiveTimeout = 10000;
client.LingerState = new LingerOption(true, 0);
var bufferSize = 1024;
byte[] buffer = new byte[bufferSize];
var isFirstPacket = true;
var startTime = DateTime.Now;
DateTime endTime = DateTime.Now;
try {
using(NetworkStream stream = client.GetStream()) {
do {
Thread.Sleep(20);
} while (!stream.DataAvailable);
while ((client != null && client.Connected) && stream != null && stream.CanRead && (endTime - startTime).TotalMinutes < 1) {
if (client == null) {
break;
}
do {
if (token.IsCancellationRequested) {
return;
}
if (client == null) {
break;
}
endTime = DateTime.Now;
int streamReadBytes = 0;
streamReadBytes = stream.Read(buffer, 0, buffer.Length);
if (streamReadBytes == 0) {
if (client != null) {
client.Close();
}
break;
}
if (buffer[0] == (byte) GalileoskyPacketHeaderEnums.FirstPacket || buffer[0] == (byte) GalileoskyPacketHeaderEnums.MainPacket) {
var parserGalileosky = new Galileosky();
var packetResult = parserGalileosky.ParsePacket(buffer, isFirstPacket);
if (packetResult == null) {
if (client != null) {
client.Close();
client = null;
}
break;
}
if (packetResult.Errors.Any()) {
if (client != null) {
client.Close();
client = null;
}
} else {
var imei = packetResult.Packet.IMEI;
if (isFirstPacket) {
isFirstPacket = false;
if (stream.CanWrite == true && packetResult.Packet.IsCrc) {
var answerPacket = packetResult.Packet.GetConfirmPacket();
stream.Write(answerPacket.Ready);
} else {
if (client != null) {
client.Close();
client = null;
}
}
} else // The Main Packet processing
{
// ... Some code to send the main packet to the app queue
if (stream.CanWrite == true && !packetResult.Errors.Any() && packetResult.Packet.IsCrc) {
var answerPacket = packetResult.Packet.GetConfirmPacket();
stream.Write(answerPacket.Ready);
}
if (packetResult.Packet.IsExtraData == false) {
if (client != null) {
client.Close();
client = null;
break;
}
}
}
}
} else {
if (client != null) {
client.Close();
client = null;
}
}
if ((endTime - startTime).TotalMinutes > 1) {
if (client != null) {
client.Close();
client = null;
break;
}
}
}
while ((client != null && client.Connected) && stream != null && stream.CanRead && stream.DataAvailable && (endTime - startTime).TotalMinutes < 1);
}
}
if (client != null) {
client.Close();
client = null;
}
} catch (Exception ex) {} finally {
if (client != null) {
client.Close();
client = null;
}
}
}
Even if your code is correct, you can hit the "2 generals" problem. There is no perfect algorithm for two parties to agree that a connection is closed, when there may be packet loss.
Gracefully closing a TCP stream requires both parties to shutdown sending, read data up to EOF, then close. I believe that you'll see a socket in CLOSE_WAIT, if one party has shutdown the connection, but the other has not. It looks like you have set your sockets to linger. In which case the operating system will take over the lifetime of the socket for you.
If your socket is not set to linger, then closing the socket early will cause data that you think you've sent to be lost.
I should also point out that your code is drastically over complicated, with error handling repeated everywhere. It looks like it was probably written before C# introduced async / await.
It also seems that you are assuming that one read operation equates to one data packet. But this is a TCP stream. The OS is allowed to fragment and recombine data that was written from one end, into any number of data reads at the other.
I'd suggest you search the internet for an example that uses .AcceptTcpClientAsync, .ReadAsync, .WriteAsync etc.
Finally I could'n find a way to solve problem to close connection within my code.
But I added a timer that close connection and it works just awesome!
private void ProcessClientRequests(object argument)
// ... The same code of my quetion
Timer timerCloseConn = new(new TimerCallback((e) =>
{
if (stream != null)
{
stream.Close();
stream.Dispose();
}
if (client != null)
{
if (client.Client.Connected)
{
client.Client.Shutdown(SocketShutdown.Both);
}
client.Close();
client.Dispose();
client = null;
}
Logger.Info("The connection has been closed by
timer's rule!");
}), null, 60000, Timeout.Infinite);
// ... The same code of my quetion
}
I've followed this article and implemented a Customer Renderer that's used to display a preview video stream from the device's camera.
I intend to capture a frame from the live stream and feed it into Tesseract OCR in order to read a number printed on a ticket.
My problem is that the image from camera preview is almost always not focused. So it is useless for its intended purpose.
An identical question has been asked years ago here in SO, but the accepted answer is not at all helpful for me.
This is the code of OnElementChanged event of CameraPreviewRenderer:
void OnElementChanged(ElementChangedEventArgs<CameraPreview> e)
{
CameraFragment newFragment = null;
if (e.OldElement != null)
{
e.OldElement.PropertyChanged -= OnElementPropertyChanged;
cameraFragment.Dispose();
}
if (e.NewElement != null)
{
this.EnsureId();
e.NewElement.PropertyChanged += OnElementPropertyChanged;
ElevationHelper.SetElevation(this, e.NewElement);
newFragment = new CameraFragment { Element = element };
}
FragmentManager.BeginTransaction()
.Replace(Id, cameraFragment = newFragment, "camera")
.Commit();
ElementChanged?.Invoke(this, new VisualElementChangedEventArgs(e.OldElement, e.NewElement));
}
This is a piece from class CameraFragment. Method RetrieveCameraDevice is the one that opens the camera (I think).
class CameraFragment : Fragment, TextureView.ISurfaceTextureListener
{
CameraDevice device;
CaptureRequest.Builder sessionBuilder;
CameraCaptureSession session;
CameraTemplate cameraTemplate;
CameraManager manager;
....
public async Task RetrieveCameraDevice(bool force = false)
{
if (Context == null || (!force && initTaskSource != null))
{
return;
}
if (device != null)
{
CloseDevice();
}
await RequestCameraPermissions();
if (!cameraPermissionsGranted)
{
return;
}
if (!captureSessionOpenCloseLock.TryAcquire(2500, TimeUnit.Milliseconds))
{
throw new RuntimeException("Timeout waiting to lock camera opening.");
}
IsBusy = true;
cameraId = GetCameraId();
if (string.IsNullOrEmpty(cameraId))
{
IsBusy = false;
captureSessionOpenCloseLock.Release();
Console.WriteLine("No camera found");
}
else
{
try
{
CameraCharacteristics characteristics = Manager.GetCameraCharacteristics(cameraId);
StreamConfigurationMap map = (StreamConfigurationMap)characteristics.Get(CameraCharacteristics.ScalerStreamConfigurationMap);
previewSize = ChooseOptimalSize(map.GetOutputSizes(Class.FromType(typeof(SurfaceTexture))),
texture.Width, texture.Height, GetMaxSize(map.GetOutputSizes((int)ImageFormatType.Jpeg)));
sensorOrientation = (int)characteristics.Get(CameraCharacteristics.SensorOrientation);
cameraType = (LensFacing)(int)characteristics.Get(CameraCharacteristics.LensFacing);
if (Resources.Configuration.Orientation == Android.Content.Res.Orientation.Landscape)
{
texture.SetAspectRatio(previewSize.Width, previewSize.Height);
}
else
{
texture.SetAspectRatio(previewSize.Height, previewSize.Width);
}
initTaskSource = new TaskCompletionSource<CameraDevice>();
Manager.OpenCamera(cameraId, new CameraStateListener
{
OnOpenedAction = device => initTaskSource?.TrySetResult(device),
OnDisconnectedAction = device =>
{
initTaskSource?.TrySetResult(null);
CloseDevice(device);
},
OnErrorAction = (device, error) =>
{
initTaskSource?.TrySetResult(device);
Console.WriteLine($"Camera device error: {error}");
CloseDevice(device);
},
OnClosedAction = device =>
{
initTaskSource?.TrySetResult(null);
CloseDevice(device);
}
}, backgroundHandler);
captureSessionOpenCloseLock.Release();
device = await initTaskSource.Task;
initTaskSource = null;
if (device != null)
{
await PrepareSession();
}
}
catch (Java.Lang.Exception ex)
{
Console.WriteLine("Failed to open camera.", ex);
Available = false;
}
finally
{
IsBusy = false;
}
}
}
I'm supposed to setup the "Focus Mode" in the Camera properties somewhere in this code. But I can't figure out a way to do this.
1 ) Its a weather Api and i want it to display no internet connection when there is no internet connected to the device.
public async void method()
{
Indicator.IsRunning = true;
Weather weather = await GetWeather(nameplace.Text);
if (weather != null)
{
if (weather.message == "city not found")
{
txtLocation.Text = "city not found";
}
else
{
Location.Text = weather.Title;
Temperature.Text = weather.Temperature;
Temperature.Text += "°";
txtWind.Text = weather.Wind;
Humidity.Text = weather.Humidity;
Sunrise.Text = weather.Sunrise;
Sunset.Text = weather.Sunset;
double condition = Convert.ToDouble(weather.Condition);
if (condition >= 0 && condition < 30)
{
Condition.Text = "Clear Sky";
}
else if (condition >= 30)
{
Condition.Text = "Cloudy";
}
}
}
else
{
await DisplayAlert("Alert", "Sorry ! No internet connection","Ok")`
}
}
3) // Below in a getservice function i have
if (Plugin.Connectivity.CrossConnectivity.Current.IsConnected)
{
var response = await client.GetAsync(QueryString);
// pQueryString is the http request
_httpStatusCode = response.StatusCode.ToString();
if (response == null)
{
return "Sorry! No record Found.";
}
else if (response != null)
{
string json = response.Content.ReadAsStringAsync().Result;
data = JsonConvert.DeserializeObject(json);
}
}
else
{
data = null;
}
return data;
4) i have return null and put a condition in there so that it can display an alert saying no internet connection
It is possible that your async void method messes with the Thread context, and that you end up not calling your code in the ui thread.
You could try this:
Xamarin.Forms.Device.BeginInvokeOnMainThread(
() => DisplayAlert("Alert", "Sorry ! No internet connection","Ok"));
Also it's a bad design to put UI code in your service layer.
Your should call your DisplayAlert code in your ViewModel not in your service.
I am writing a packet sniffer using C# and PcapDotNet, I've successfully implemented the feature and I was able to capture all the TCP packets from my laptop, the problem is if I target my android device I get no packets at all,
I am a beginner at networking, so I think I am probably missing something.
This is my code for the packet handler, I am using an ObjectListView with a model object that contains all the information I want to list, also I have the network adapter in Promiscuous mode with a Berkeley filter to get only TCP packets with port numbers 443 and 80 that contains data (No SYN, FIN, ACK-only packets) from a specific Mac address
Code:
private void PacketHandler(PcapDotNet.Packets.Packet packet)
{
if (packet == null) { return; }
if (packet.Ethernet == null) { return; }
if (packet.Ethernet.IpV4 == null) { return; }
if (packet.Ethernet.IpV4.Tcp == null) { return; }
if (packet.Ethernet.IpV4.Tcp.Http == null) { return; }
var acpacket = new AcceptedPacket(); //Model Object
acpacket.Packet = packet;
try
{
HttpDatagram http = packet.Ethernet.IpV4.Tcp.Http;
if (packet.Ethernet.Source.ToString() == targetmac)
{
if (http.IsRequest && http.IsValid)
{
if (materialListView1.InvokeRequired)
{
materialListView1.BeginInvoke(new Action(() => {
materialListView1.AddObject(acpacket); }));
}
else
{
materialListView1.AddObject(acpacket);
}
ListofAcceptedPackets.Add(acpacket);
}
}
}
catch (Exception ex)
{
MetroMessageBox.Show(this, ex.Message, "Error",
MessageBoxButtons.OK,
MessageBoxIcon.Error);
}
}
And this how I opened the adapter :
using (communicator =
selectedDevice.Open(65536,PacketDeviceOpenAttributes.Promiscuous,
1000))
{
if (communicator.DataLink.Kind !=
DataLinkKind.Ethernet)
{
if (MetroMessageBox.Show(this, "Only Ethernet is supported in this operation!","Error", MessageBoxButtons.OK,MessageBoxIcon.Error) == DialogResult.OK)
{
return;
}
}
using (BerkeleyPacketFilter filter = communicator.CreateFilter($"tcp port 80 and (((ip[2:2] - ((ip[0]&0xf)<<2)) - ((tcp[12]&0xf0)>>2)) != 0) and ether src {targetmac.ToLower()} or tcp port 443 and (((ip[2:2] - ((ip[0]&0xf)<<2)) - ((tcp[12]&0xf0)>>2)) != 0) and ether src {targetmac.ToLower()}"))
{
communicator.SetFilter(filter);
}
flag = true;
Packet packet;
do
{
PacketCommunicatorReceiveResult result =
communicator.ReceivePacket(out packet);
switch (result)
{
case
PacketCommunicatorReceiveResult.Timeout:
continue;
case
PacketCommunicatorReceiveResult.Ok:
{
PacketHandler(packet);
}
break;
default:
break;
}
} while (flag);
}
I also tried without any filter and couldn't reach the android device packets.
so is it possible to capture TCP packets from other devices on the network besides my own device? or maybe there's something wrong with my implementation?
Edit: after trying a bit more I was able to successfully get the TCP packets from the android device but only while implementing ARP Cache Poisoning at the same time because the device thinks that I am the gateway. so my question stands, can this be done without ARP Cache Poisoning because I think it's a bit aggressive for a packet sniffer.
I was finally able to make it work by applying ARP cache poisoning while the code below is able to redirect packets for any device to their destination, this way you get to capture packets for any device on the network specifically without losing internet access for this device.
Code:
private void StartSniffer()
{
RawCapture rawCapture;
do
{
if ((rawCapture = capturedevice.GetNextPacket()) != null)
{
EthernetPacket Packet = PacketDotNet.Packet.ParsePacket(rawCapture.LinkLayerType, rawCapture.Data) as EthernetPacket;
if (Packet == null) { return; }
AcceptedPacket acPacket = new AcceptedPacket();
acPacket.Packet = Packet;
if (Packet.SourceHwAddress.Equals(TargetMAC))
{
Packet.SourceHwAddress = capturedevice.MacAddress;
Packet.DestinationHwAddress = GatewayMAC;
capturedevice.SendPacket(Packet);
if (acPacket.TCPPacket != null &&
((acPacket.Type.Equals("HTTPS") && acPacket.TCPPacket.PayloadData != null) ||
(acPacket.Type.Equals("HTTP") && acPacket.TCPPacket.PayloadData != null)))
{
materialListView1.BeginInvoke(new Action(() =>
{
materialListView1.AddObject(acPacket);
if (materialListView1.Items.Count > 15 && !ResizeDone)
{
olvColumn8.MaximumWidth = 65;
olvColumn8.MinimumWidth = 65;
olvColumn8.Width = 65;
ResizeDone = true;
}
ListofAcceptedPackets.Add(acPacket);
}));
}
}
else if (Packet.SourceHwAddress.Equals(GatewayMAC))
{
IPv4Packet IPV4 = Packet.Extract(typeof(IPv4Packet)) as IPv4Packet;
if (IPV4.DestinationAddress.Equals(Target))
{
Packet.SourceHwAddress = capturedevice.MacAddress;
Packet.DestinationHwAddress = TargetMAC;
capturedevice.SendPacket(Packet);
}
if (Properties.Settings.Default.PacketDirection == "Inbound")
{
if (acPacket.TCPPacket != null &&
((acPacket.Type.Equals("HTTPS") && acPacket.TCPPacket.PayloadData != null) ||
(acPacket.Type.Equals("HTTP") && acPacket.TCPPacket.PayloadData != null)))
{
materialListView1.BeginInvoke(new Action(() =>
{
materialListView1.AddObject(acPacket);
if (materialListView1.Items.Count > 15 && !ResizeDone)
{
olvColumn8.MaximumWidth = 65;
olvColumn8.MinimumWidth = 65;
olvColumn8.Width = 65;
ResizeDone = true;
}
ListofAcceptedPackets.Add(acPacket);
}));
}
}
}
}
} while (snifferStarted);
And this is the capture device setup:
try
{
snifferStarted = true;
if (capturedevice != null)
{
capturedevice.Open(DeviceMode.Promiscuous, 1000);
capturedevice.Filter = $"(ip and ether src {targetmac.ToLower()}) or (ip and ether src {gatewayMAC.ToLower()} and dst net {Target})";
new Thread(() => { StartSniffer(); }).Start();
}
else
{
MetroMessageBox.Show(this, "No Capture Device is selected!", "Error", MessageBoxButtons.OK,
MessageBoxIcon.Error);
}
}
catch (Exception exception)
{
MetroMessageBox.Show(this, exception.Message, "Error", MessageBoxButtons.OK,
MessageBoxIcon.Error);
}
Note: this has been done using Packet.Net NOT PcapDotNet.
I have a recursive function in a windows service. This function upon completion rewinds itself as it has been repeated multiple times in recursion. Isn't that an overhead ?
Is there any way to avoid unwinding ? Is there any better approach?
Edit : In this method, I get 100 records from DB and then process them and then get another 100 and so on till all the records in DB have been processed.
Also, there is no limit of how many total records there might be in the db so this function can repeat itself quite a lot.
public void ServiceFunctionality()
{
try
{
// Get Data From WEBAPI
HttpClient client = new HttpClient();
HttpResponseMessage response = response = client.GetAsync("webapi url link").Result;
Response<ServiceWrapper> objResponse = response.Content.ReadAsAsync<Response<ServiceWrapper>>().Result;
if (objResponse != null)
{
if (objResponse.isSuccess == true)
{
listContact = objResponse.data.lContact;
int MaxPKinSelectedRecords = objResponse.data.MaxPKinSelectedRecords;
int MaxPKinTotalRecords = objResponse.data.MaxPKinTotalRecords;
if (listContact != null && listContact.Count>0)
{
try
{
Parallel.ForEach(listContact, contact =>
{
// some code...
});
// Recursive Call
if (MaxPKinTotalRecords != MaxPKinSelectedRecords)
{
ServiceFunctionality();
}
}
catch (Exception ex)
{
// Logging
}
}
}
else
{
// Logging
}
}
else
{
// Logging
}
}
catch (Exception ex)
{
// Logging
}
}
You can always unwind to a while loop. Because your calls aren't altering state, this is trival.
public void ServiceFunctionality()
{
bool done = false;
while(!done) {
try
{
done = true; //if we don't reset this, we're done.
// Get Data From WEBAPI
HttpClient client = new HttpClient();
HttpResponseMessage response = response = client.GetAsync("webapi url link").Result;
Response<ServiceWrapper> objResponse = response.Content.ReadAsAsync<Response<ServiceWrapper>>().Result;
if (objResponse != null)
{
if (objResponse.isSuccess == true)
{
listContact = objResponse.data.lContact;
int MaxPKinSelectedRecords = objResponse.data.MaxPKinSelectedRecords;
int MaxPKinTotalRecords = objResponse.data.MaxPKinTotalRecords;
if (listContact != null && listContact.Count>0)
{
try
{
Parallel.ForEach(listContact, contact =>
{
// some code...
});
// set loop variable
if (MaxPKinTotalRecords != MaxPKinSelectedRecords)
{
done = false;
}
}
catch (Exception ex)
{
// Logging
}
}
}
else
{
// Logging
}
}
else
{
// Logging
}
}
catch (Exception ex)
{
// Logging
}
}
}
Do not use recursion for calling a function whenever you have alternate suitable solution. I personally almost never do
I have tried to keep it same other than using a while..
Do not forget to break your loop. I tried to handle this thing but still
Just to be very careful, never take a risk of infinite loop on server I took maxPossibleIterations. So that in case of any mistake your web service server would not have to go for infinite iterations
public void ServiceFunctionality()
{
long maxPossibleIterations = 999999;
try
{
while (true)
{
maxPossibleIterations++;
// Get Data From WEBAPI
HttpClient client = new HttpClient();
HttpResponseMessage response = response = client.GetAsync("webapi url link").Result;
Response<ServiceWrapper> objResponse = response.Content.ReadAsAsync<Response<ServiceWrapper>>().Result;
if (objResponse != null)
{
if (objResponse.isSuccess == true)
{
listContact = objResponse.data.lContact;
int MaxPKinSelectedRecords = objResponse.data.MaxPKinSelectedRecords;
int MaxPKinTotalRecords = objResponse.data.MaxPKinTotalRecords;
if (listContact != null && listContact.Count>0)
{
try
{
Parallel.ForEach(listContact, contact =>
{
// some code...
});
if (MaxPKinTotalRecords == MaxPKinSelectedRecords)
{
break;
}
}
catch (Exception ex)
{
// Logging
}
}
else
break; //Important
}
else
{
// Logging
break;
}
}
else
{
// Logging
break;
}
} // End while
}
catch (Exception ex)
{
// Logging
}
}