I want to check the instrument connectivity, continuously. These instruments are connected by LAN.
I ping them in an infinite loop. After a few seconds, I'm met with a blue screen and the system restarts.
private async void checkingDevice()
{
await Task.Run(() =>
{
do
{
Panel selectedPanel;
multicastPing.send();
foreach (var device in (Device[])Enum.GetValues(typeof(Device)))
{
selectedPanel = (Panel)this.Controls.Find((device).ToString(), true)[0];
if (multicastPing.check(device.ToString()))
selectedPanel.BackgroundImage = Image.FromFile(Configs.imagesUrl + "enable\\" + selectedPanel.AccessibleName + ".png");
else
selectedPanel.BackgroundImage = Image.FromFile(Configs.imagesUrl + "disable\\" + selectedPanel.AccessibleName + ".png");
}
} while (!flag);
// TODO
// delete instrument object after using in this snippet code
});
}
public bool send()
{
foreach (var device in (Device[])Enum.GetValues(typeof(Device)))
replyDictionary[device.ToString()] = sendDictionary[device.ToString()].Send(Configs.instrumentSpecification[device.ToString()].ip).Status;
return true;
}
My career was in Test and Measurement and doing this kind of thing seems quite familiar. So I'm offering this as one approach to see if I can assist you in pinging your instrument stack.
Getting a blue screen is pretty rare and just from personal experience it's likely that a very low-level IO kernel driver (ethernet port?) is having a bad time of something. Potentially, it appears that the loop could run very fast to the point of overrunning a buffer perhaps? Or, pathologically, you may inadvertently be binding the UI thread to that of a kernel driver one. Ouch.
I agree with comments about safely calling the UI thread from a task using MethodInvoker. But I think perhaps the main issue might be coming from the fact that this loop "runs as fast as it can" which might be pretty fast. I modeled something like this that throttles the pings so that they occur some limited number of times per second and it seems to work fine.
A safely-threaded task that performs the look without ever blocking on the UI thread looks something like this:
CancellationTokenSource _cts = null;
SemaphoreSlim ssBusy = new SemaphoreSlim(1);
private void ExecMulticastPing()
{
ssBusy.Wait();
Task.Run(() =>
{
try
{
_cts = new CancellationTokenSource();
do
{
List<Task<PingReply>> asyncPings = new List<Task<PingReply>>();
// Sends out the pings in rapid succession to execute asynchronously in parallel
foreach (var device in (Device[])Enum.GetValues(typeof(Device)))
{
asyncPings.Add(Task.Run(() => SinglePingAsync(device, _cts.Token)));
}
// Waits for all the async pings to complete.
Task.WaitAll(asyncPings.ToArray());
// See if flag is already cancelled
if (_cts.IsCancellationRequested) break;
foreach (var device in (Device[])Enum.GetValues(typeof(Device)))
{
SetPanelImage(device, asyncPings[(int)device].Result);
}
// I believe that it's very important to throttle this to
// a reasonable number of repeats per second.
Task.Delay(1000).Wait();
BeginInvoke((MethodInvoker)delegate
{
WriteLine(); // Newline
});
} while (!_cts.IsCancellationRequested); // Check if it's cancelled now
}
finally
{
ssBusy.Release();
}
BeginInvoke((MethodInvoker)delegate
{
WriteLine("CANCELLED");
});
});
}
... where ...
const string URL_FOR_TEST = #"www.ivsoftware.com";
private PingReply SinglePingAsync(Device device, CancellationToken token)
{
if(token.IsCancellationRequested)
{
return null;
}
Ping pingSender = new Ping();
PingOptions options = new PingOptions()
{
DontFragment = true
};
PingReply reply = pingSender.Send(URL_FOR_TEST);
BeginInvoke((MethodInvoker)delegate
{
if (reply.Status == IPStatus.Success)
{
WriteLine("Address: " + reply.Address.ToString());
WriteLine("RoundTrip time: " + reply.RoundtripTime);
WriteLine("Time to live: " + reply.Options.Ttl);
WriteLine("Don't fragment: " + reply.Options.DontFragment);
WriteLine("Buffer size: " + reply.Buffer.Length);
WriteLine();
}
else
{
WriteLine("REQUEST TIMEOUT");
}
});
return reply;
}
... and ...
private void SetPanelImage(Device device, PingReply reply)
{
BeginInvoke((MethodInvoker)delegate
{
WriteLine("Setting panel image for " + device.ToString() + " " + reply.Status.ToString() );
Panel selectedPanel = (
from Control unk in Controls
where
(unk is Panel) &&
(unk.Name == device.ToString()) // ... or however you go about finding the panel...
select unk as Panel
).FirstOrDefault();
if (selectedPanel != null)
{
switch (reply.Status)
{
case IPStatus.Success:
// Set image for enabled
break;
case IPStatus.TimedOut:
// Set image as disabled
break;
default:
// Set image as disabled
break;
}
}
});
}
This 10-second screen capture demonstrates the success of this approach and you can browse the complete example code on our GitHub repo if you think this would be helpful. I also answered a different-but-related question here.
Related
I have an asynchronous function. It is called only once when the form is displayed for the first time. My function should ping devices asynchronously when I open the program. But it turns out that when you close the child form, another poll is launched. Tell me where the error may be.
Function call (I tried to call it in formLoad):
private async void MainForm_Shown(object sender, EventArgs e)
{
await Start();
}
Function itself:
public async Task Start()
{
while (keyOprosDev)
{
for (int i = 0; i < devicesListActivity.Count; i++)
{
devicesListActivity[i].DevicesList.DevicesTotalPing++;
string ipAdresDevice = devicesListActivity[i].DevicesList.DevicesName;
int portDevice = devicesListActivity[i].DevicesList.DevicesPort;
int activeDevice = devicesListActivity[i].DevicesList.DevicesActiv;
int sendTimeDevice = devicesListActivity[i].DevicesList.DevicesTimeSend;
int respTimeDevice = devicesListActivity[i].DevicesList.DevicesTimeResp;
using (TcpClient client = new TcpClient())
{
if (activeDevice == 1)
{
client.SendTimeout = sendTimeDevice;
client.ReceiveTimeout = respTimeDevice;
var ca = client.ConnectAsync(ipAdresDevice, portDevice);
await Task.WhenAny(ca, Task.Delay(sendTimeDevice));
client.Close();
if (ca.IsFaulted || !ca.IsCompleted)
{
textBox1.AppendText($"{DateTime.Now.ToString()} Server refused connection." + " " + ipAdresDevice + string.Format(" [{0}/{1}]", devicesListActivity[i].DevicesList.DevicesSuccessPing, devicesListActivity[i].DevicesList.DevicesTotalPing) + " " + System.Math.Round((double)(devicesListActivity[i].DevicesList.DevicesSuccessPing / devicesListActivity[i].DevicesList.DevicesTotalPing * 100)) + " %");
textBox1.AppendText("\r\n");
devicesListActivity[i].DevicesList.DevicesImage = 1;
}
else
{
devicesListActivity[i].DevicesList.DevicesSuccessPing++;
textBox1.AppendText($"{DateTime.Now.ToString()} Server available" + " " + ipAdresDevice + string.Format(" [{0}/{1}]", devicesListActivity[i].DevicesList.DevicesSuccessPing, devicesListActivity[i].DevicesList.DevicesTotalPing) + " " + System.Math.Round((double)(devicesListActivity[i].DevicesList.DevicesSuccessPing / devicesListActivity[i].DevicesList.DevicesTotalPing * 100)) + " %");
textBox1.AppendText("\r\n");
devicesListActivity[i].DevicesList.DevicesImage = 2;
}
}
else
{
}
}
await Task.Delay(interval);
}
}
}
And here is the opening of the child form:
try
{
DbViewer dbViewer = new DbViewer();
dbViewer.FormClosed += new FormClosedEventHandler(refr_FormClosed);
dbViewer.ShowDialog();
}
catch (Exception ex)
{
writeEventInDb(ex.Message);
}
This is the event that handles the closure of the child form:
void refr_FormClosed(object sender, FormClosedEventArgs e)
{
try
{
kryptonTreeView1.Nodes[0].Nodes[0].Nodes.Clear();
kryptonTreeView1.Nodes[0].Nodes[1].Nodes.Clear();
loadIpListFromDb();
loadComListFromDb();
kryptonTreeView1.ExpandAll();
}
catch (Exception ex)
{
writeEventInDb(ex.Message);
}
}
You need to pass a cancellation token in. Somewhere outside of this code you need to create a CancellationTokenSource the best place is probably an property of the form:
class MainForm
{
CancellationTokenSource cts;
...
You then initialize this and pass this to Start():
private async void MainForm_Shown(object sender, EventArgs e)
{
cts = new CancellationTokenSource();
CancellationToken ct = cts.Token;
await Start(ct);
}
In your start loop you need to monitor for the cancellation token:
Because you're using a delay to timeout the ConnectAsync() you need the Task.Delay() to know when cancellation is requested so you need to pass the token to Task.Delay():
await Task.WhenAny(ca, Task.Delay(sendTimeDevice,ct));
After the TcpClient.Close() you need to test if the cancellation is requested, and stop loops if it is:
if (ct.IsCancellationRequested)
break;
You'll need to perform the same test in the while loop, and also you should perform it immediately before the ConnectAsync(). While the most likely place you will encounter ct.IsCancellationRequested == true will be immediately after the Task.WhenyAny or immediately after the Loop interval there's no point starting a ConnectAsync() if cancellation has been requested.
You should also pass the CancellationToken to the Loop interval, otherwise you could end up waiting interval before your form closes:
// This will throw an OperationCancelled Exception if it is cancelled.
await Task.Delay(interval,ct);
Because you're going to continue anyway and just exit if Cancellation is registered you could avoid writing a separate try/catch that does nothing and await the interval like this, it's almost certainly less efficient, but it's cleaner.
// Leave any exceptions of Task.Delay() unobserved and continue
await Task.WhenAny(Task.Delay(interval,ct));
Finally you need to dispose of the CancellationTokenSource, I guess you would do this in something like a MainForm_Closed() function?
private void MainForm_Closed(object sender, EventArgs e)
{
cts.Dispose();
The only thing left to do is to work out when you want to fire the CancellationRequest, based on what you have said you want to do this when the form close button has been clicked, so:
private void MainForm_Closing(object sender, EventArgs e)
{
cts.Cancel();
That will cause the CancellationToken to transition to a cancelled state and your Start() routine will see that and exit.
In your code there is no single place to check for the CancellationToken being set, the rule of thumb is to check for it before and after any await and in your case you should check for it in both the while and the for loop.
I am trying to ping one of my servers using C# Ping to see whether it is available or not, but I am receiving a weird error and I'm not sure what's causing it
On first execution of the code, it returns an error but states that the operation was completed successfully
System.Net.Sockets.SocketException (0x80004005): The operation completed successfully.\r\n\r\n at System.Net.Sockets.Socket..ctor (System.Net.Sockets.AddressFamily addressFamily, System.Net.Sockets.SocketType socketType, System.Net.Sockets.ProtocolType protocolType) [0x00069]
Each time the code is executed after the first, it will return a different error.
"An attempt was made to access a socket in a way forbidden by its access permissions."
System.Net.Sockets.SocketException (0x80004005)
The code I am using to ping is as follows which is pretty much pulled straight from MSDN. https://msdn.microsoft.com/en-us/library/system.net.networkinformation.pingreply(v=vs.110).aspx
public static bool pingHost(string nameOrAddress)
{
bool pingable = false;
if (nameOrAddress == "127.0.0.1")
{
return true;
}
try
{
System.Net.NetworkInformation.Ping pingSender = new System.Net.NetworkInformation.Ping();
PingOptions options = new PingOptions();
// Use the default Ttl value which is 128,
// but change the fragmentation behavior.
options.DontFragment = true;
// Create a buffer of 32 bytes of data to be transmitted.
string data = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
byte[] buffer = Encoding.ASCII.GetBytes(data);
int timeout = 3;//3 seconds?
PingReply reply = pingSender.Send(nameOrAddress, timeout);
if (reply.Status == IPStatus.Success)
{
pingable = true;
} else
{
pingable = false;
}
}
catch (PingException e)
{
Debug.Log("Error pinging: " + e.Message + " - " + e.StackTrace);
// Discard PingExceptions and return false;
}
return pingable;
}
I am able to ping the server from my terminal on my machine, but not through code. Why am I receiving this error?
EDIT
I have tested the code in a standard C# application and it works fine. This issue must be something related to Unity.
Unity has its own Ping class but can't be called from outside the main thread. The code below tries to utilise this, but it always returns false and -1 for the time.
Ping should definitely complete within 3 seconds? I have tried increasing this time to 10 seconds but still returns false. The address is definitely pingable as I can ping it from the terminal.
IEnumerator ping()
{
while (true)
{
UnityEngine.Ping pinger = new UnityEngine.Ping("ADDRESS");
yield return new WaitForSeconds(3.0f);
Debug.Log("Ping finished? " + pinger.isDone + " - " + pinger.time);
yield return new WaitForSeconds(2.0f);
}
}
As this doesn't work, my next question is how does the Unity ping actually work? My servers are in a secure environment with only specific open ports. If it is doing something unexpected other than the standard ping, it may not be able to.
EDIT 2
IEnumerator ping()
{
while (true)
{
WaitForSeconds f = new WaitForSeconds(0.05f);
Ping p = new Ping("ADDR");
while (!p.isDone)
{
yield return f;
}
PingFinished(p);
}
}
This code seems to work nicely, but only works from the main thread. I will need a solution that is able to be started from a separate task or thread.
This seems to work, but only from the main thread.
IEnumerator ping()
{
while (true)
{
WaitForSeconds f = new WaitForSeconds(0.05f);
Ping p = new Ping("ADDR");
while (!p.isDone)
{
yield return f;
}
PingFinished(p);
}
}
Here's a general idea of how to do it on/off the main thread:
(Caution: untested)
using System.Threading;
class Test : MonoBehaviour {
Ping result;
private object pingLock;
void Start() {
pingLock = new object();
new Thread(ThingRunningOffMainThread).Start();
StartCoroutine(DoPing());
}
IEnumerator DoPing()
{
WaitForSeconds f = new WaitForSeconds(0.05f);
Ping p = new Ping("ADDR");
while (!p.isDone)
{
yield return f;
}
Monitor.Enter(pingLock);
result = p;
Monitor.Pulse(pingLock);
Monitor.Exit(pingLock);
}
void ThingRunningOffMainThread() {
if (result == null) {
Monitor.Enter(pingLock);
while (result == null) {
Monitor.Wait(pingLock);
}
Monitor.Exit(pingLock);
}
PingFinished(pingLock);
}
}
To invoke from a background thread to the main thread, look at Main Thread Dispatchers, for example:
https://github.com/PimDeWitte/UnityMainThreadDispatcher/blob/master/UnityMainThreadDispatcher.cs
I spent a couple of days searching in Google and trying to understand why in my case Windows Forms UI is blocked when executing pings in Tasks.
I saw a lot of similar cases, but none of them explains my specific case.
Issue description:
I have an application which sends pings asynchronously. Each ping is send inside of a Task. I use .ContinueWith to receive result of a ping and print it to textbox without blocking UI thread. It works OK if I launch all pings once. If I add a while {run} loop to make them run forever my UI becomes unresponsive and blocked, and none of the results are printed to the textbox.
Problematic Code:
Action action2 = () => {
for (int i = 0; i < ipquantity; i++)
{
int temp1 = i;
string ip = listView1.Items[temp1].SubItems[1].Text;
if (finished[temp1] == true) // Variable helps to check if ping reply was received and printed
continutask[temp1] = Task<string>.Run(() => PingStart(ip, temp1)).ContinueWith(antecedent => PrintResult(antecedent.Result, temp1));
}
};
while (run)
{
action2();
Thread.Sleep(1000);
}
Questions:
Why is the UI blocked with a while loop and why is it not blocked without it?
How can I modify my code to be still able to use Tasks for pings without blocking the UI?
Is there a better way to launch endless pings to several IP addresses simultaneously?
Complete code:
private async void buttonStart_Click(object sender, EventArgs e)
{
run = true;
int count = listView1.Items.Count;
task = new Task<string>[count];
result1 = new string[count];
finished = new bool[count];
continutask = new Task[count];
for (int i = 0; i < count; i++)
{
finished[i] = true;
}
Action action2 = () =>
{
for (int i = 0; i < count; i++)
{
int temp1 = i;
string ip = listView1.Items[temp1].SubItems[1].Text;
if (finished[temp1] == true)
continutask[temp1] = Task<string>.Run(() => PingStart(ip, temp1)).ContinueWith(antecedent => PrintResult(antecedent.Result, temp1));
}
};
while (run)
{
action2();
//await Task.Delay;
//Thread.Sleep(1000);
}
}
public void PrintResult(string message, int seqnum)
{
Action action = () =>
{
textBox1.AppendText(message);
textBox1.AppendText(Environment.NewLine);
textBox1.AppendText("");
textBox1.AppendText(Environment.NewLine);
};
if (InvokeRequired)
Invoke(action);
else
action();
finished[seqnum] = true;
}
public string PingStart(string ip, int seqnum)
{
finished[seqnum] = false;
Ping isPing = new Ping();
PingReply reply;
const int timeout = 2000;
const string data = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
var buffer = Encoding.ASCII.GetBytes(data);
PingOptions options = new PingOptions();
// Use the default Ttl value which is 128,
options.DontFragment = false;
reply = isPing.Send(ip, timeout, buffer, options);
string rtt = (reply.RoundtripTime.ToString());
string success = "N/A";
if (reply.Status == IPStatus.Success)
{
success = $"{ip}" + " Success!" + $" rtt: [{rtt}]" + $"Thread: {Thread.CurrentThread.GetHashCode()} Is pool thread: {Thread.CurrentThread.IsThreadPoolThread}";
}
else if (reply.Status != IPStatus.Success)
{
success = $"{ip}" + $" Not Successful! Status: {reply.Status}" + $"Thread: {Thread.CurrentThread.GetHashCode()} Is pool thread: {Thread.CurrentThread.IsThreadPoolThread}";
}
return success;
}
Since you already create (and save) your tasks, the easiest fix would be to await them for each iteration of your while loop:
while (run)
{
action2();
foreach (Task t in continutask)
await t;
}
That way, when all pings completed (successful or not) you start the entire process again - without delay.
One more thing: You could add a textBox1.ScrollToEnd(); to PrintResult
Since there is a lot of room for improvement, below is a rewritten and simplified example. I've removed a lot of unused variables (e.g. seqnum) and made the PingStart method completely asynchronous. I also replaced your ListBox with a TextBox for easier testing, so you might want to revert that in your code.
This still isn't the cleanest of all possible implementations (mainly because of the global run) but it should show you how to do things "more async" :)
private async void buttonStart_Click(object sender, EventArgs e)
{
// If the ping loops are already running, don't start them again
if (run)
return;
run = true;
// Get all IPs (in my case from a TextBox instead of a ListBox
string[] ips = txtIPs.Text.Split(new[] {"\r\n"}, StringSplitOptions.RemoveEmptyEntries);
// Create an array to store all Tasks
Task[] pingTasks = new Task[ips.Length];
// Loop through all IPs
for(int i = 0; i < ips.Length; i++)
{
string ip = ips[i];
// Launch and store a task for each IP
pingTasks[i] = Task.Run(async () =>
{
// while run is true, ping over and over again
while (run)
{
// Ping IP and wait for result (instead of storing it an a global array)
var result = await PingStart(ip);
// Print the result (here I removed seqnum)
PrintResult(result.Item2);
// This line is optional.
// If you want to blast pings without delay,
// you can remove it
await Task.Delay(1000);
}
}
);
}
// Wait for all loops to end after setting run = false.
// You could add a mechanism to call isPing.SendAsyncCancel() instead of waiting after setting run = false
foreach (Task pingTask in pingTasks)
await pingTask;
}
// (very) simplified explanation of changes:
// async = this method is async (and therefore awaitable)
// Task<> = This async method returns a result of type ...
// Tuple<bool, string> = A generic combination of a bool and a string
// (-)int seqnum = wasn't used so I removed it
private async Task<Tuple<bool, string>> PingStart(string ip)
{
Ping isPing = new Ping();
const int timeout = 2000;
const string data = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
var buffer = Encoding.ASCII.GetBytes(data);
PingOptions options = new PingOptions {DontFragment = false};
// await SendPingAsync = Ping and wait without blocking
PingReply reply = await isPing.SendPingAsync(ip, timeout, buffer, options);
string rtt = reply.RoundtripTime.ToString();
bool success = reply.Status == IPStatus.Success;
string text;
if (success)
{
text = $"{ip}" + " Success!" + $" rtt: [{rtt}]" + $"Thread: {Thread.CurrentThread.GetHashCode()} Is pool thread: {Thread.CurrentThread.IsThreadPoolThread}";
}
else
{
text = $"{ip}" + $" Not Successful! Status: {reply.Status}" + $"Thread: {Thread.CurrentThread.GetHashCode()} Is pool thread: {Thread.CurrentThread.IsThreadPoolThread}";
}
// return if the ping was successful and the status message
return new Tuple<bool, string>(success, text);
}
This way you will have a loop for each IP that will continue independently of each other until run is set to false.
Thread.Sleep(n) blocks the current thread for n milliseconds. If I understand the code correctly it executes action2 then suspends the calling thread for one second. If that thread is the main (UI) thread, your UI will be blocked.
Maybe moving the while loop to yet another thread would fix the problem.
I have this code to download data from multiple websites.
I need to run this code for about 50.000 times.
However after running the code for 2 minutes (about 4000 times) I get the TaskCanceledException and my CPU goes to 100% and my process slows down incredibly.
This is the code:
public async Task<string[]> GetDataAsync(string address, string postalCode)
{
var path = $"{address} {postalCode}/"; // build proper path for request
var textFrom1 = "";
string textFrom3 = "";
string textFrom2 = "";
while (true)
{
try
{
textFrom1 = await client.GetStringAsync("http://website1.com/" + path);
break;
}
catch (Exception e) //404
{
await Task.Delay(10000); // try every 10 seconds (so I do not bomb the server with requests).
}
}
if (textFrom1.Split(':', ',')[1] == "0")
{
return new string[] { "null", "null", "null", "null", "null" };
}
while (true)
{
try
{
textFrom2 = await client.GetStringAsync("http://website2.com/" + textFrom1.Split('"', '"')[11]);
break;
}
catch (Exception e)
{
await Task.Delay(10000);
}
}
while (true)
{
try
{
textFrom3 = await client.GetStringAsync("http://website3.com/" + textFrom2.Split('"', '"')[3]);
break;
}
catch (Exception e)
{
await Task.Delay(10000);
}
}
var allData = await Task.Run(() => JsonConvert.DeserializeObject<List<RootObject>>(textFrom3));
var item = allData.First();
return new string[] { item.item1, item.item2, item.item3, item.item4, item.item5 };
}
And this is the way I create my tasks:
public string[][] GetAll(
IEnumerable<string> adresses,
IEnumerable<string> postalCodes)
{
// Start all tasks one by one without waiting for responses
var tasks = adresses.Zip(postalCodes, (addr, code) => { return GetDataAsync(addr, code); });
return Task.WhenAll(tasks).Result;
}
Is there any way I can optimize my code, so that I do not have this exception and therefor not slowing down my process?
I hope someone can help me, thank you!
I think you are reaching the maximum number of tasks windows can handle at once. You could split your 50.000 requests to smaller groups or write some code to handle your running async-tasks to make sure that you don't start too much tasks at once.
Furthermore you probably reach the maximum number of ports. Everytime starting a new connection your application will open a new dynamic port.
Hey guys this is my first attempt at using the Task libraries in 4.0 so if you see anything else I'm besides my problem that is not correct please do let me know.
My problem is that when I schedule a bunch of task which inside use a webclient to make a request, the first few make it through just fine, but after a certain time my webclient starts throwing an exception. It as if it creates the webclient then sticks in the Task and waits for a thread to pick it up but by that time the timeout time is reached .. that's just my assumption.
Here is the code :
var TmsThread = Task.Factory.StartNew(() => UpdateTmsNullPackages(), TaskCreationOptions.LongRunning);
that runs in the Form1_Load of the windows app. This is what it calls
public void UpdateTmsNullPackages()
{
Parallel.ForEach(TmsNullPackages, Package =>
{
try
{
Task<string> task = Task.Factory.StartNew(() => Package.GetPackageTmsId(), TaskCreationOptions.AttachedToParent);
task.ContinueWith(t =>
{
if (!String.IsNullOrEmpty(t.Result))
{
Package.TMSID = t.Result;
NowTmsIdFoundPackages.Add(Package);
}
});
}
catch(Exception ex){}
});
}
which in turn, runs this
public static string GetPackageTmsId(this TwcPackage Package)
{
string TMSID = null;
if (!(String.IsNullOrEmpty(Package.movie_Provider)) && !(String.IsNullOrEmpty(Package.movie_Product)) && !(String.IsNullOrEmpty(Package.movie_Provider_ID)) && !(String.IsNullOrEmpty(Package.movie_Asset_ID)))
{
try
{
using (WebClient client = new WebClient())
{
client.Credentials = new NetworkCredential(TMSID_Recheck.Properties.Settings.Default.WebRequestUser, TMSID_Recheck.Properties.Settings.Default.WebRequestProdUserPassWord);
XmlDocument xmlDoc = new XmlDocument();
string URLToBeRequested = TMSID_Recheck.Properties.Settings.Default.RequestProdBaseURL + TMSID_Recheck.Properties.Settings.Default.RequestAPIVersion + "/" + TMSID_Recheck.Properties.Settings.Default.RequestAPIProgramServiceCall + TMSID_Recheck.Properties.Settings.Default.RequestAPIProgramAssociationServiceCall + Package.movie_Provider + ':' + Package.movie_Product + ':' + Package.movie_Provider_ID + "::" + Package.movie_Asset_ID;
try
{
xmlDoc.LoadXml(client.DownloadString(URLToBeRequested));
XmlNodeList Program = xmlDoc.DocumentElement.SelectNodes("program");
if (Program.Count > 0) TMSID = Program[0].Attributes["TMSId"].Value.ToString();
}
catch (WebException ex)
{
if (ex.Status != WebExceptionStatus.Timeout)
{
if (((HttpWebResponse)ex.Response).StatusCode != HttpStatusCode.NotFound) { }
}
else { }
}
}
}
catch (Exception ix) { }
}
return TMSID;
}
the issue happens when downloadstring is called after a couple hundred tasks it throws a timeout exception.
the issue happens when downloadstring is called after a couple hundred tasks
And how many tasks have completed in that time slice?
It looks like you are simply queuing too many requests. Your system and the remote server probably have policies in place to limit the number of simultaneous connections.
The solution (and a quick diagnosis test) would be to use MaxDegreeOfParallelism in the ForEach.
Here is a similar question with some good answers.