Continuous Async Ping inside a Windows Service - c#

I need to monitor a list of hosts continuously. After N seconds, i need to check the list again. So, I tried to use the async ping inside a Windows Service.
I tried to follow tips from other posts related to the topic, but always my service stops shortly after starting it.
There are a problem with await in "OnElapsedTime" function.
Any one have an idea what is wrong? Bellow my code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.Threading.Tasks;
using System.Timers;
using System.Net.NetworkInformation;
namespace PingAsyncService
{
public partial class HyBrazil_Ping : ServiceBase
{
Timer timer = new Timer();
List<string> IPList = new List<string>(); //List of IPs
public HyBrazil_Ping()
{
IPList.Add("192.168.0.1");
IPList.Add("192.168.0.254");
InitializeComponent();
}
protected override void OnStart(string[] args)
{
WriteToFile("Service is started at " + DateTime.Now);
timer.Elapsed += new ElapsedEventHandler(OnElapsedTime);
timer.Interval = 5000; //number in miliseconds
timer.Enabled = true;
}
protected override void OnStop()
{
WriteToFile("Service is stopped at " + DateTime.Now);
}
private async void OnElapsedTime(object source, ElapsedEventArgs e)
{
//WriteToFile("Service is recall at " + DateTime.Now);
var ResultList = await PingAsync();
foreach(PingReply reply in ResultList)
{
WriteToFile(reply.Address.ToString() + ";" + reply.Status.ToString());
}
}
private async Task<PingReply> PingAndProcessAsync(Ping pingSender, string ip)
{
var result = await pingSender.SendPingAsync(ip, 2000);
return result;
}
private async Task<List<PingReply>> PingAsync()
{
Ping pingSender = new Ping();
var tasks = IPList.Select(ip => PingAndProcessAsync(pingSender, ip));
var results = await Task.WhenAll(tasks);
return results.ToList();
}
public void WriteToFile(string Message)
{
string path = AppDomain.CurrentDomain.BaseDirectory + "\\Logs";
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}
string filepath = AppDomain.CurrentDomain.BaseDirectory + "\\Logs\\ServiceLog_" + DateTime.Now.Date.ToShortDateString().Replace('/', '_') + ".txt";
if (!File.Exists(filepath))
{
// Create a file to write to.
using (StreamWriter sw = File.CreateText(filepath))
{
sw.WriteLine(Message);
}
}
else
{
using (StreamWriter sw = File.AppendText(filepath))
{
sw.WriteLine(Message);
}
}
}
}
}
Thanks a lot!

In one of the comments you mentioned the error message as
"An asynchronous call is already in progress. It must be completed or canceled before you can call this method."
Chances are, the Ping object does not let simultaneous asynchronous calls.
Using a new Ping object everytime, on each call, might help as below.
private async Task<List<PingReply>> PingAsync()
{
// Ping pingSender = new Ping();
var tasks = IPList.Select(ip =>
{
using (var p= new Ping())
{
return PingAndProcessAsync(p, ip);
}
});
var results = await Task.WhenAll(tasks);
return results.ToList();
}

Related

Unable to start Windows Service if reference is used

I have create a windows service. when i try to start the service, i recieve the error
Windows could not start the Auto Process service on Local Computer.
Error 1053: The service did not respond to the start or control request in a timely fashion.
This is my code
using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;
using System.ServiceProcess;
using System.Timers;
using Drone.Engine; //
namespace Auto
{
public partial class Service1 : ServiceBase
{
static string month = DateTime.Now.ToString("MMM");
private Timer timer = new Timer();
private Dictionary<string, bool> processStatus = new Dictionary<string, bool>();
private Executor worker = new Executor(); //
public Service1()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
processStatus.Add("start", false);
processStatus.Add("stop", false);
System.Threading.Thread.Sleep(10000);
WriteToFile("Service Started at " + DateTime.Now);
timer.Elapsed += new ElapsedEventHandler(OnElapsedTime);
timer.Interval = 2000;
timer.Enabled = true;
}
private void OnElapsedTime(object sender, ElapsedEventArgs e)
{
foreach (var process in processStatus.Where(v => v.Value == false))
{
WriteToFile(process.Key + " Sync Started at " + DateTime.Now);
ChangeProcessStatus(process.Key, true);
worker.Execute(Executor.sender.Navision, process.Key); //
ChangeProcessStatus(process.Key, false);
WriteToFile(process.Key + " Sync Finished at " + DateTime.Now);
}
}
protected override void OnStop()
{
WriteToFile("Service stopped at " + DateTime.Now);
}
private void ChangeProcessStatus(string key, bool status)
{
processStatus[key] = status;
}
public void WriteToFile(string Message)
{
string path = AppDomain.CurrentDomain.BaseDirectory + "\\data\\logs";
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}
string filepath = AppDomain.CurrentDomain.BaseDirectory + "\\data\\logs\\ServiceLog_" + DateTime.Now.Date.Day + " " + month + ".log";
if (!File.Exists(filepath))
{
using (StreamWriter sw = File.CreateText(filepath))
{
sw.WriteLine(Message);
}
}
else
{
using (StreamWriter sw = File.AppendText(filepath))
{
sw.WriteLine(Message);
}
}
}
}
}
But if i remove the lines
using Drone.Engine;
The service is starting successfully. Why am i unable to use it in the service?
The dll is present in the same directory. I have used the release build for installing. Still this issue.
Previously i was using filepaths like
filePath=#"data\log";
This was working fine in my application. But when i reference it to my windows service, i was getting System.IO.DirectoryNotFoundException error.
I changed the filepath to
filepath=AppDomain.CurrentDomain.BaseDirectory + "\\data\\logs";
It worked for both my service and application.

C# - FTP Upload Using UploadFileAsync With Progress on Console

I'm new to C# and I wanted to do an FTP upload with progress showing on console. My code is as below from some help from MSDN examples.
using System;
using System.Net;
using System.IO;
using System.Threading.Tasks;
namespace FTPUpload
{
class FTPClient
{
public void Upload()
{
string localFile = #"D:\Applications\python-3.3.0.msi";
string destPath = "ftp://127.0.0.1/python-3.3.0.msi";
if (File.Exists(localFile))
{
Console.WriteLine(localFile + " exists!");
}
else
{
Console.WriteLine(localFile + " doesn't exists!");
}
using (WebClient client = new WebClient())
{
client.Credentials = new NetworkCredential("Anonymous", "Anonymous");
client.UploadProgressChanged += new UploadProgressChangedEventHandler(UploadProgressCallback);
client.UploadFileCompleted += new UploadFileCompletedEventHandler(UploadCompleted);
client.UploadFileAsync(new Uri(destPath), localFile);
Console.WriteLine("Upload started");
}
}
public void UploadProgressCallback(object sender, UploadProgressChangedEventArgs e)
{
Console.WriteLine(e.TotalBytesToSend);
}
public void UploadCompleted(object sender, UploadFileCompletedEventArgs e)
{
Console.WriteLine(e.Result);
}
public static void Main(string[] args)
{
FTPClient ftpClient = new FTPClient();
ftpClient.Upload();
}
}
}
I think I have not written it properly and I tried to search in Google can't find any examples with respect to this.
Kindly point me in right direction.
I have seen this but not able to get the point
File is not uploaded to FTP server on some machines when using WebClient.UploadFileAsync
Thanks!

C# Windows Phone 8.1 GetOutputStreamAsync(...) blocking after first use

i'm currently trying to create a very basic test app which should:
1) Broadcast "sometext" on port "1234"
2) Wait a second for answers
3) Return all answers
While the solution posted below works fine for the first time, every subsequent call blocks forever at:
stream = await socket.GetOutputStreamAsync(...)
Till now i tried every possible way of cleaning up (since thats where i suppose the failure), even wrapping everything in using(...) statements.
The problem occurs with the emulator as well as a hardware device using Windows Phone 8.1
Thanks in advance!
The code to start the "discovery":
private void Button_Click(object sender, RoutedEventArgs e)
{
PluginUDP pudp = new PluginUDP();
var task = pudp.scan("asf");
task.Wait();
foreach (string s in task.Result)
output.Text += s + "\r\n";
}
The code for the "discovery" itself:
using System;
using Windows.Networking;
using Windows.Networking.Sockets;
using Windows.Storage.Streams;
using System.Text;
using System.IO;
using System.Threading.Tasks;
using System.Collections.Concurrent;
using namespace whatever
{
public class PluginUDP
{
private static readonly HostName BroadcastAddress = new HostName("255.255.255.255");
private static readonly string BroadcastPort = "1234";
private static readonly byte[] data = Encoding.UTF8.GetBytes("00wlan-ping00");
ConcurrentBag<string> receivers;
public async System.Threading.Tasks.Task<string[]> scan(string options)
{
receivers = new ConcurrentBag<string>();
receivers.Add("ok");
DatagramSocket socket = null;
IOutputStream stream = null;
DataWriter writer = null;
try
{
socket = new DatagramSocket();
socket.MessageReceived += MessageReceived;
await socket.BindServiceNameAsync("");
stream = await socket.GetOutputStreamAsync(BroadcastAddress, BroadcastPort);
writer = new DataWriter(stream);
writer.WriteBytes(data);
await writer.StoreAsync();
Task.Delay(1000).Wait();
}
catch (Exception exception)
{
receivers.Add(exception.Message);
}
finally
{
if (writer != null)
{
writer.DetachStream();
writer.Dispose();
}
if(stream != null)
stream.Dispose();
if(socket != null)
socket.Dispose();
}
return receivers.ToArray(); ;
}
private async void MessageReceived(DatagramSocket socket, DatagramSocketMessageReceivedEventArgs args)
{
try
{
var result = args.GetDataStream();
var resultStream = result.AsStreamForRead(1024);
using (var reader = new StreamReader(resultStream))
{
var text = await reader.ReadToEndAsync();
if (text.Contains("pong"))
{
receivers.Add(args.RemoteAddress.ToString());
}
}
}
catch (Exception exception)
{
receivers.Add("ERRCV");
}
}
}
}
Your problem starts here:
task.Wait();
You're blocking on async code, which leads you to a deadlock.
You want:
private async void Button_Click(object sender, RoutedEventArgs e)
{
PluginUDP pudp = new PluginUDP();
string[] result = await pudp.scan("asf");
foreach (string s in result)
output.Text += s + "\r\n";
}
You also want to do:
await Task.Delay(1000);
Instead of:
Task.Delay(1000).Wait();

Bluetooth Server C# - 32feet

I want my computer to be a bluetooth server, handlig at least 100 connections from smartphones simultaneously. This is the idea:
I start the server and it begin to listen for connections. For each connection it should store the mac adress of the device. Each device should be able to send messages to the server and vice versa.
I've been searching a lot but didnt find a certain way.
How to listen for connections and handle them? Store in array? Start A Thread?
I've been able to start a 1 client server, but coudnt evolve it.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Threading;
using InTheHand.Net.Bluetooth;
using InTheHand.Net.Ports;
using InTheHand.Net.Sockets;
using System.IO;
namespace BluetoothChamada
{
public partial class Form1 : Form
{
List<string> items;
String clientConectedName, clientConectedMAC;
public Form1()
{
InitializeComponent();
items = new List<string>();
}
private void bGo_Click(object sender, EventArgs e)
{
if (serverStarted)
{
updateUI("---Servidor já foi Iniciado---");
return;
}
if (rbServer.Checked)
{
connectAsServer();
}
else
{
Scan();
}
}
private void startScan()
{
listBox1.DataSource = null;
listBox1.Items.Clear();
items.Clear();
Thread bluetoothScanThread = new Thread(new ThreadStart(Scan));
bluetoothScanThread.Start();
}
BluetoothDeviceInfo[] devices;
private void Scan()
{
updateUI("Procurando dispositivos...");
BluetoothClient client = new BluetoothClient();
devices = client.DiscoverDevicesInRange();
updateUI("Procura finalizada");
updateUI(devices.Length.ToString() + " dispositivos encontrados");
foreach (BluetoothDeviceInfo d in devices)
{
items.Add(d.DeviceName);
}
updateDeviceList();
}
private void connectAsServer()
{
Thread bluetoothServerThread = new Thread(new ThreadStart(ServerConnectThread));
bluetoothServerThread.Start();
}
Guid mUUID = new Guid("00001101-0000-1000-8000-00805F9B34FB");
bool serverStarted = false;
public void ServerConnectThread()
{
serverStarted = true;
BluetoothListener blueListener = new BluetoothListener(mUUID);
blueListener.Start();
updateUI("---Servidor Iniciado, aguardando clientes---\r\n\n");
BluetoothClient connection = blueListener.AcceptBluetoothClient();
getData();
updateUI("Cliente: " + clientConectedName + "\r\nMac: " + clientConectedMAC);
Stream mStream = connection.GetStream();
while (true)
{
try
{
byte[] received = new byte[1024];
mStream.Read(received, 0, received.Length);
updateUI(System.Environment.NewLine + "Recebido: " + Encoding.ASCII.GetString(received));
byte[] sent = Encoding.ASCII.GetBytes("FeedBack: OK \r\n");
mStream.Write(sent, 0, sent.Length);
}
catch (IOException exception)
{
updateUI("Cliente foi desconectado");
break;
}
}
}
private void getData()
{
BluetoothClient client = new BluetoothClient();
BluetoothDeviceInfo[] devices = client.DiscoverDevices();
foreach (BluetoothDeviceInfo device in devices)
{
if (!device.Connected)
{
}
else
{
clientConectedName = device.DeviceName;
clientConectedMAC = device.DeviceAddress.ToString();
}
}
}
private void updateUI(string message)
{
Func<int> del = delegate()
{
tbOutput.AppendText(message + System.Environment.NewLine);
return 0;
};
Invoke(del);
}
private void updateDeviceList()
{
Func<int> del = delegate()
{
listBox1.DataSource = items;
return 0;
};
Invoke(del);
}
}
}

Download multiple files in parallel using c#

I want to download files in parallel using C#. For this, I have written this code which is working perfectly but the problem is that UI is freezing.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;
namespace FileDownloader
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private static int count = 1;
private static string f= "lecture";
private string URL = "www.someexample.com";
public MainWindow()
{
InitializeComponent();
}
public static string GetDirectoryListingRegexForUrl(string url)
{
if (url.Equals(URL))
{
return "(?<name>.*)";
}
throw new NotSupportedException();
}
public void DownloadP(string[] urls)
{
Parallel.ForEach(urls.ToList(), new ParallelOptions { MaxDegreeOfParallelism = 10 }, DownloadFile);
}
private void DownloadFile(string url)
{
using(WebClient client=new WebClient())
{
if (url.EndsWith(".pdf"))
{
int nextIndex = Interlocked.Increment(ref count);
client.DownloadFile(url, f + nextIndex + ".pdf");
this.Dispatcher.Invoke(() => {
listbox.Items.Add(url);
});
}
}
}
private void Button_Click(object sender, RoutedEventArgs e)
{
DownloadP(listofFiles);
}
}
}
You can use async/await with conjunction with new WebClient method DownloadFileTaskAsync.
private async Task DownloadFile(string url)
{
if (!url.EndsWith(".pdf"))
{
return;
}
using (var client = new WebClient())
{
int nextIndex = Interlocked.Increment(ref count);
await client.DownloadFileTaskAsync(url, "lecture" + nextIndex + ".pdf");
listBox.Items.Add(url);
}
}
private async void Button_OnClick(object sender, RoutedEventArgs e)
{
button.IsEnabled = false;
await DownloadFiles(urlList);
button.IsEnabled = true;
}
private async Task DownloadFiles(IEnumerable<string> urlList)
{
foreach (var url in urlList)
{
await DownloadFile(url);
}
}
Relace your DownloadP function with this :
public async Task DownloadP(string[] urls)
{
await Task.Factory.StartNew(() => Parallel.ForEach(urls.ToList(), new ParallelOptions { MaxDegreeOfParallelism = 10 }, DownloadFile));
}
instead of using client.DownloadFile use client.DownloadFileAsync like this
var webClient=new WebClient();
webClient.DownloadFileCompleted += webClient_DownloadFileCompleted;
webClient.DownloadFileAsync("Your url","file_name");
the event
private void webClient_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
MessageBox.Show("Download Completed.");
}
I know this Question is old, but WebClient is outdated and dedicated.
First of all, WPF uses MVVM pattern that you should try to follow, but except that you can use the HttpClient in using System.Net.Http;.
To download multiple files in a parallel you can create a parallel foreach that handles all the downloads that the HttpClient have to perform. You did tis right but the foreach will block the thread so start it in a new one Task.Run(()=>{// Your Code});
In the case you don’t want do write something like that yourself, you could use the Shard Download Library on NuGet. This NuGet Package is also on GitHub if you want to see how it does its job. It helped me often if I want do download a lot of files, because is does not block the UI thread and is easy to use. To use it you have to write something like this:
void Download()
{
string[] links = new string[]{
"https://google.com",
"https://speed.hetzner.de/100MB.bin",
"https://file-examples.com/storage/fe88dacf086398d1c98749c/2017/04/file_example_MP4_1920_18MG.mp4" };
foreach (var link in links)
{
_ = new LoadRequest(link);
}
Console.ReadLine();
}
But you can also set the MaxDegreeOfParalism and you can change it while it is downloading. You can set the Path for the output file and name it. The problem that the HttpClient has with download finished and progress report is also solved with this. The bad thing is that the documentation of this library is not very good. Here an example with few options as an example.
async Task DownloadAsync()
{
string[] links = new string[]{
"https://google.com",
"https://speed.hetzner.de/100MB.bin",
"https://file-examples.com/storage/fe88dacf086398d1c98749c/2017/04/file_example_MP4_1920_18MG.mp4" };
RequestHandler requestHandler = new()
{
MaxDegreeOfParallelism = 10
};
LoadRequestOptions option = new()
{
Progress = new Progress<float>(value => Console.WriteLine(value.ToString("0.0%"))),
DestinationPath = "C:\\Users\\[UserName]\\Desktop\\",
RequestCompleated = path => Console.WriteLine("Finished: " + path?.ToString()),
RequestHandler = requestHandler
};
LoadRequest last = null;
foreach (string link in links)
{
last = new LoadRequest(link, option);
}
await last.Task;
}
I hope that can help people that have the same problem and don’t want to use the dedicated WebClient.

Categories