Bloomberg web service call for single field and single instrument taking more than 1 min - c#

I am making a Bloomberg web service GetData call for the "DEBT_TO_EQUITY_FUNDAMENTALS_TKR" field. I am setting secmaster = true and asking for a single instrument with a CUSIP identifier (with yellowkey = MarketSector.Corp).
This strikes me as a fairly lightweight call having seen people asking for thousands of instruments and dozens of fields at once.
I have played around with setting lots of different settings but I just can't get this request to return in a few seconds. It gives me the correct return value but it takes longer than 60 seconds.
Any idea if it is possible to get such a request to execute and return in a few seconds?
Thanks
EDIT - Here is the code I am running:
public string GetFundamentalTicker(string identifier, InstrumentType identifierType = InstrumentType.CUSIP)
{
PerSecurityWS ps = new PerSecurityWS();
try
{
log.DebugFormat("Cert path is: {0}", CertPath);
X509Certificate2 clientCert = new X509Certificate2(CertPath, "<password_redacted>");
ps.ClientCertificates.Add(clientCert);
}
catch (Exception e)
{
log.ErrorFormat("Error in cert setup - {0} - {1}", e.Message, e.InnerException == null ? "" : e.InnerException.Message);
return null;
}
//Set request header
GetDataHeaders getDataHeaders = new GetDataHeaders();
getDataHeaders.secmaster = true;
getDataHeaders.secmasterSpecified = true;
//getDataHeaders.fundamentals = true;
//getDataHeaders.fundamentalsSpecified = true;
//getDataHeaders.programflag = ProgramFlag.oneshot;//unnecessary - defaults to this anyway
//getDataHeaders.programflagSpecified = true;
//getDataHeaders.pricing = true;
getDataHeaders.secid = identifierType;
getDataHeaders.secidSpecified = true;
SubmitGetDataRequest sbmtGtDtreq = new SubmitGetDataRequest();
sbmtGtDtreq.headers = getDataHeaders;
sbmtGtDtreq.fields = new string[] {
"DEBT_TO_EQUITY_FUNDAMENTALS_TKR"
};
int currentFundYear = DateTime.Now.Year;
//var fundYears = new List<int>();
List<Instrument> fundYearInstruments = new List<Instrument>();
Instrument fundYearInstrument = null;
fundYearInstrument = new Instrument();
fundYearInstrument.id = identifier;
fundYearInstrument.typeSpecified = true;
fundYearInstrument.type = identifierType;
fundYearInstrument.yellowkey = MarketSector.Corp;
fundYearInstrument.yellowkeySpecified = true;
//fundYearInstrument.overrides = new Override[] {};//{ new Override() { field = "EQY_FUND_YEAR", value = currentFundYear.ToString() } };
fundYearInstruments.Add(fundYearInstrument);
//fundYears.Add(-1);
Instrument[] instr = fundYearInstruments.ToArray();
Instruments instrs = new Instruments();
instrs.instrument = instr;
sbmtGtDtreq.instruments = instrs;
try
{
SubmitGetDataResponse sbmtGtDtResp = ps.submitGetDataRequest(sbmtGtDtreq);
RetrieveGetDataRequest rtrvGtDrReq = new RetrieveGetDataRequest();
rtrvGtDrReq.responseId = sbmtGtDtResp.responseId;
RetrieveGetDataResponse rtrvGtDrResp;
do
{
System.Threading.Thread.Sleep(POLL_INTERVAL);
rtrvGtDrResp = ps.retrieveGetDataResponse(rtrvGtDrReq);
}
while (rtrvGtDrResp.statusCode.code == DATA_NOT_AVAILABLE);
if (rtrvGtDrResp.statusCode.code == SUCCESS)
{
for (int i = 0; i < rtrvGtDrResp.instrumentDatas.Length; i++)
{
for (int j = 0; j < rtrvGtDrResp.instrumentDatas[i].data.Length; j++)
{
if (rtrvGtDrResp.instrumentDatas[i].data[j].value == "N.A." || rtrvGtDrResp.instrumentDatas[i].data[j].value == "N.S." || rtrvGtDrResp.instrumentDatas[i].data[j].value == "N.D.")
rtrvGtDrResp.instrumentDatas[i].data[j].value = null;
return rtrvGtDrResp.instrumentDatas[i].data[j].value;
}
}
return null;
}
else if (rtrvGtDrResp.statusCode.code == REQUEST_ERROR)
{
log.ErrorFormat("Error in the submitted request: {0}", rtrvGtDrResp.statusCode.description);
return null;
}
}
catch (Exception e)
{
log.ErrorFormat("Error in GetData - {0} - {1}", e.Message, e.InnerException == null ? "" : e.InnerException.Message);
return null;
}
return null;
}
Poll interval is 5 seconds and the SOAP web service url is:
https://software.bloomberg.com/datalicensewp/dlws.wsdl

I am having the same issue. I found out that there is a difference between making the same call to Bloomberg API from, for example, console app (works very fast) and web service (takes a lot of time to start session). And the difference is that console app runs under the same user as bbcomm process, whereas web service (or actually iis process) runs under System account. You can try to log out all users on the PC where web service is hosted and then try to make the call. In this case, I guess, bbcomm goes under System account as no one else is logged in and works fast. It worked for me and the call was answered instantly.

Related

C# WUApiLib know if a windows update needs a restart

I use this code to get pending windows updates and also most of the informations of the update:
static List<PendingUpdate> GetPendingUpdates()
{
var updateSession = new UpdateSession();
var updateSearcher = updateSession.CreateUpdateSearcher();
updateSearcher.Online = false; //set to true if you want to search online
List<PendingUpdate> pendingUpdates = new List<PendingUpdate>();
try
{
var searchResult = updateSearcher.Search("IsInstalled=0 And IsHidden=0");
if (searchResult.Updates.Count > 0)
{
Console.WriteLine("There are updates available for installation");
foreach (IUpdate windowsUpdate in searchResult.Updates)
{
PendingUpdate update = new PendingUpdate();
update.Title = windowsUpdate.Title;
update.Description = windowsUpdate.Description;
update.Downloaded = windowsUpdate.IsDownloaded;
update.Urls = new List<string>();
foreach (string url in windowsUpdate.MoreInfoUrls)
{
update.Urls.Add(url);
}
foreach (dynamic category in windowsUpdate.Categories)
{
update.Categories += category.Name + ", ";
}
pendingUpdates.Add(update);
}
}
}
catch (Exception ex)
{
Console.WriteLine("ERROR");
throw ex;
}
return pendingUpdates;
}
I also use this code to get to know if the computer currently needs a restart to finish installed updates:
static bool needsRestart()
{
ISystemInformation systemInfo = new SystemInformation();
return systemInfo.RebootRequired;
}
Now my question is, is it possible to get to know if an pending update needs a computer restart to finish? In the first code I get a IUpdate object but I dont see informations about a needed restart after installing this update. I there a way to get this information?
For the asynchronous installation I use something like this:
rebootRequired = false;
UpdateSession updateSession = new UpdateSession();
updateSession.ClientApplicationID = SusClientID;
IUpdateInstaller updatesInstaller = updateSession.CreateUpdateInstaller();
IInstallationJob job = updatesInstaller.BeginInstall(InstallProgressCallback, installComplete, installState);
// here is your installer code and the checking if the installation is completed
IInstallationProgress jobProgress = job.GetProgress();
for (int updateindex = 0; updateindex < updatesInstaller.Updates.Count; updateindex++)
{
IUpdateInstallationResult updateInstallResult = jobProgress.GetUpdateResult(updateindex);
rebootRequired |= updateInstallResult.RebootRequired;
}
if(rebootRequired)
{
// any of the updates need a reboot
}

Adwords Api How to Pause Ads on Ad level

I am trying to PAUSE the Ads with the AdId and AdGroupID. I have successfully paused an AdGroup but i want to pause Ads individually. Is this possible on Adwords API. I tried the code below but It seems it only works on AdGroup level. Also checked the AdService but seems that there is no option to edit the Status.
I am using Ads.AdWords.v201809
Thanks in advance
public void googleEnableDisableAds(AdWordsUser user, long adGroupId, long AdID, AdGroupAdStatus AdStatus)
{
using (AdGroupAdService adGroupAdService =
(AdGroupAdService)user.GetService(AdWordsService.v201809.AdGroupAdService))
{
List<AdGroupAdOperation> operations = new List<AdGroupAdOperation>();
// Create the expanded text ad.
ExpandedTextAd expandedTextAd = new ExpandedTextAd
{
//CR[i].
id = AdID
};
AdGroupAd expandedTextAdGroupAd = new AdGroupAd
{
adGroupId = adGroupId,
ad = expandedTextAd,
// Optional: Set the status.
status = AdStatus
};
// Create the operation.
AdGroupAdOperation operation = new AdGroupAdOperation
{
#operator = Operator.SET,
operand = expandedTextAdGroupAd
};
operations.Add(operation);
AdGroupAdReturnValue retVal = null;
try
{
if (operations.Count > 0)
{
// Create the ads.
retVal = adGroupAdService.mutate(operations.ToArray());
// Display the results.
if (retVal != null && retVal.value != null)
{
foreach (AdGroupAd adGroupAd in retVal.value)
{
ExpandedTextAd newAd = adGroupAd.ad as ExpandedTextAd;
Console.WriteLine(
"Expanded text ad with ID '{0}' and headline '{1} - {2}' " +
"was added.", newAd.id, newAd.headlinePart1, newAd.headlinePart2);
//adGroupId
}
}
else
{
Console.WriteLine("No expanded text ads were created.");
}
}
adGroupAdService.Close();
}
catch (Exception e)
{
throw new System.ApplicationException("Failed to create expanded text ad.", e);
}
}
}
Here is an example from API docs https://developers.google.com/adwords/api/docs/samples/csharp/basic-operations#pause-an-ad
The key idea is to set status property to PAUSED
AdGroupAdStatus status = AdGroupAdStatus.PAUSED

Multithreaded c# console app to scrape data from sites

I have written an app that goes through our own properties and scraps the data. To make sure I don't run through the same URLs, I am using a MySQL database to store the URL, flag it once its processed. All this was being done in a single thread and it's fine if I had only few thousand entries. But I have few hundred thousand entries that I need to parse so I need to make changes in the code (I am newbie in multithreading in general). I found an example and was trying to copy the style but doesn't seem to work. Anyone know what the issue is with the following code?
EDIT: Sorry didn't mean to make people guess the issue but was stupid of me to include the exception. Here is the exception
"System.InValidCastException: 'Specified cast is not valid.'"
When I start the process it collects the URLs from the database and then never hits DoWork method
//This will get the entries from the database
List<Mappings> items = bot.GetUrlsToProcess(100);
if (items != null)
{
var tokenSource = new CancellationTokenSource();
var token = tokenSource.Token;
Worker.Done = new Worker.DoneDelegate(WorkerDone);
foreach (var item in items)
{
urls.Add(item.Url);
WaitingTasks.Enqueue(new Task(id => new Worker().DoWork((int)id, item.Url, token), item.Url, token));
}
LaunchTasks();
}
static async void LaunchTasks()
{
// keep checking until we're done
while ((WaitingTasks.Count > 0) || (RunningTasks.Count > 0))
{
// launch tasks when there's room
while ((WaitingTasks.Count > 0) && (RunningTasks.Count < MaxRunningTasks))
{
Task task = WaitingTasks.Dequeue();
lock (RunningTasks) RunningTasks.Add((int)task.AsyncState, task);
task.Start();
}
UpdateConsole();
await Task.Delay(300); // wait before checking again
}
UpdateConsole(); // all done
}
static void UpdateConsole()
{
Console.Write(string.Format("\rwaiting: {0,3:##0} running: {1,3:##0} ", WaitingTasks.Count, RunningTasks.Count));
}
static void WorkerDone(int id)
{
lock (RunningTasks) RunningTasks.Remove(id);
}
public class Worker
{
public delegate void DoneDelegate(int taskId);
public static DoneDelegate Done { private get; set; }
public async void DoWork(object id, string url, CancellationToken token)
{
if (token.IsCancellationRequested) return;
Content obj;
try
{
int tries = 0;
bool IsUrlProcessed = true;
DateTime dtStart = DateTime.Now;
string articleDate = string.Empty;
try
{
ScrapeWeb bot = new ScrapeWeb();
SearchApi searchApi = new SearchApi();
SearchHits searchHits = searchApi.Url(url, 5, 0);
if (searchHits.Hits.Count() == 0)
{
obj = await bot.ReturnArticleObject(url);
if (obj.Code != HttpStatusCode.OK)
{
Console.WriteLine(string.Format("\r Status is {0}", obj.Code));
tries = itemfound.UrlMaxTries + 1;
IsUrlProcessed = false;
itemfound.HttpCode = obj.Code;
}
else
{
string title = obj.Title;
string content = obj.Contents;
string description = obj.Description;
Articles article = new Articles();
article.Site = url.GetSite();
article.Content = content;
article.Title = title;
article.Url = url.ToLower();
article.Description = description;
string strThumbNail = HtmlHelper.GetImageUrl(url, obj.RawResponse);
article.Author = HtmlHelper.GetAuthor(url, obj.RawResponse);
if (!string.IsNullOrEmpty(strThumbNail))
{
//This condition needs to be added to remove ?n=<number> from EP thumbnails
if (strThumbNail.Contains("?"))
{
article.ImageUrl = strThumbNail.Substring(0, strThumbNail.IndexOf("?")).Replace("http:", "https:");
}
else
article.ImageUrl = strThumbNail.Replace("http:", "https:");
}
else
{
article.ImageUrl = string.IsNullOrEmpty(strThumbNail) ? article.Url.GetDefaultImageUrls() : strThumbNail.Replace("http:", "https:");
}
articleDate = HtmlHelper.GetPublishDate(url, obj.RawResponse);
if (string.IsNullOrEmpty(articleDate))
article.Pubdate = DateTime.Now;
else
article.Pubdate = DateTime.Parse(articleDate);
var client = new Index(searchApi);
var result = client.Upsert(article);
itemfound.HttpCode = obj.Code;
if (result)
{
itemfound.DateCreated = DateTime.Parse(articleDate);
itemfound.DateModified = DateTime.Parse(articleDate);
UpdateItem(itemfound);
}
else
{
tries = itemfound.UrlMaxTries + 1;
IsUrlProcessed = false;
itemfound.DateCreated = DateTime.Parse(articleDate);
itemfound.DateModified = DateTime.Parse(articleDate) == null ? DateTime.Now : DateTime.Parse(articleDate);
UpdateItem(itemfound, tries, IsUrlProcessed);
}
}
}
else
{
tries = itemfound.UrlMaxTries + 1;
IsUrlProcessed = true;
itemfound.HttpCode = HttpStatusCode.OK;
itemfound.DateCreated = DateTime.Parse(articleDate);
itemfound.DateModified = DateTime.Parse(articleDate) == null ? DateTime.Now : DateTime.Parse(articleDate);
}
}
catch (Exception e)
{
tries = itemfound.UrlMaxTries + 1;
IsUrlProcessed = false;
itemfound.DateCreated = DateTime.Parse(articleDate);
itemfound.DateModified = DateTime.Parse(articleDate) == null ? DateTime.Now : DateTime.Parse(articleDate);
}
finally
{
DateTime dtEnd = DateTime.Now;
Console.WriteLine(string.Format("\r Total time taken to process items is {0}", (dtEnd - dtStart).TotalSeconds));
}
}
catch (Exception e)
{
Console.WriteLine(e);
}
Done((int)id);
}
}
All this code is based from Best multi-thread approach for multiple web requests this link. Can someone tell me how to get this approach running?
I think the problem is in the way you're creating your tasks:
new Task(id => new Worker().DoWork((int)id, item.Url, token), item.Url, token)
This Task constructor overload expected Action<object> delegate. That means id will be typed as object and you need to cast it back to something useful first.
Parameters
action
Type: System.Action<Object>
The delegate that represents the code to execute in the task.
state
Type: System.Object
An object representing data to be used by the action.
cancellationToken
Type: System.Threading.CancellationToken
-The CancellationToken that that the new task will observe.
You decided to cast it to int by calling (int)id, but you're passing item.Url as the object itself. I can't tell you 100% what the type of Url is but I don't expect Url-named property to be of type int.
Based on what #MarcinJuraszek said I just went back to my code and added an int as I couldn't find another way to resolve it. Here is the change I made
int i=0
foreach (var item in items)
{
urls.Add(item.Url);
WaitingTasks.Enqueue(new Task(id => new Worker().DoWork((string)id, item.Url, token), item.Url, token));
i++;
}

How can I search Notes by sequence number

I use Evernote C# API. I understand how filters working.
ENNoteStoreClient store = ENSessionAdvanced.SharedSession.PrimaryNoteStore;
SyncState currentState = store.GetSyncState();
int currentUpdateCount = currentState.UpdateCount;
if (currentUpdateCount > latestUpdateCount)
{
latestUpdateCount = currentUpdateCount;
// Here synchronization code
}
I have latestUpdateCount and how I can get notes with sequence number >= this number?
You'll want to use GetFilteredSyncChunk using code something like the following:
List<SyncChunk> syncBlocks = new List<SyncChunk>();
int maxEntries = 250;
// These are sample filter settings; you should use what's appropriate for you based on
// what data you want returned in your note objects.
SyncChunkFilter filter = new SyncChunkFilter();
filter.IncludeNotes = true;
filter.IncludeNoteAttributes = true;
filter.IncludeNotebooks = true;
filter.IncludeTags = false;
filter.IncludeSearches = false;
filter.IncludeResources = false;
filter.IncludeLinkedNotebooks = false;
filter.IncludeExpunged = false;
filter.IncludeNoteApplicationDataFullMap = false;
filter.IncludeResourceApplicationDataFullMap = false;
filter.IncludeNoteResourceApplicationDataFullMap = false;
do
{
SyncChunk chunk = store.getFilteredSyncChunk(currentUpdateCount, maxEntries, filter);
if (chunk == null)
{
return null; // This can happen if there is a "503 - Service unavailable" error accessing this person's Evernote info
}
syncBlocks.Add(chunk);
currentUpdateCount = chunk.ChunkHighUSN;
} while (currentUpdateCount < serverSyncState.UpdateCount);
foreach (SyncChunk chunk in syncBlocks)
{
if (chunk != null && chunk.Notes != null)
{
foreach (Note chunkNote in chunk.Notes)
{
// do something with the retrieved chunkNote object
}
}
}

C# false http response

I have a thread that returns a site's http response status, but sometimes my program returns false results. and after a while it gives good results.
False result:
it takes a big a mount of time to check, and then it says that (for example) Google is down, which is quite not reasonable, but after a few seconds it returns good results
Can you take a look and tell me whats wrong? or how I can I improve it?
Checks all sites in datagrid:
private void CheckSites()
{
if (CheckSelected())
{
int rowCount = dataGrid.BindingContext[dataGrid.DataSource, dataGrid.DataMember].Count;
string url;
for (int i = 0; i < rowCount; i++)
{
url = dataGrid.Rows[i].Cells[2].Value.ToString();
if (url != null)
{
Task<string[]> task = Task.Factory.StartNew<string[]>
(() => checkSite(url));
// We can do other work here and it will execute in parallel:
//Loading...
// When we need the task's return value, we query its Result property:
// If it's still executing, the current thread will now block (wait)
// until the task finishes:
string[] result = task.Result;
selectRows();
if (result[0] != System.Net.HttpStatusCode.OK.ToString() && result[0] != System.Net.HttpStatusCode.Found.ToString() && result[0] != System.Net.HttpStatusCode.MovedPermanently.ToString())
{
//bad
notifyIcon1.ShowBalloonTip(5000, "Site Down", dataGrid.Rows[i].Cells[2].Value.ToString() + ", has a status code of:" + result, ToolTipIcon.Error);
dataGrid.Rows[i].DefaultCellStyle.BackColor = System.Drawing.Color.Wheat;
TimeSpan ts;
TimeSpan timeTaken = TimeSpan.Parse(result[1]);
dataGrid.Rows[i].Cells[3].Value = result[0];
dataGrid.Rows[i].Cells[3].Style.BackColor = System.Drawing.Color.Red;
dataGrid.Rows[i].Cells[4].Value = timeTaken.Seconds.ToString() + "." + String.Format("{0:0.00000}", timeTaken.Milliseconds.ToString()) + " seconds.";
string sec = (DateTime.Now.Second < 10) ? "0" + DateTime.Now.Second.ToString() : DateTime.Now.Second.ToString();
string min = (DateTime.Now.Minute < 10) ? "0" + DateTime.Now.Minute.ToString() : DateTime.Now.Minute.ToString();
string hour = (DateTime.Now.Hour < 10) ? "0" + DateTime.Now.Hour.ToString() : DateTime.Now.Hour.ToString();
dataGrid.Rows[i].Cells[5].Value = hour + ":" + min + ":" + sec;
//loadbar
}
else if (result[0] == "catch")//catch
{
notifyIcon1.ShowBalloonTip(10000, "SITE DOWN", dataGrid.Rows[i].Cells[1].Value.ToString() + ", Error:" +result[1], ToolTipIcon.Error);
dataGrid.Rows[i].Cells[3].Value = result[1];
dataGrid.Rows[i].Cells[3].Style.BackColor = System.Drawing.Color.Red;
//loadbar
}
else
{
//good
TimeSpan timeTaken = TimeSpan.Parse(result[1]);
dataGrid.Rows[i].Cells[3].Value = result[0];
dataGrid.Rows[i].Cells[3].Style.BackColor = System.Drawing.Color.LightGreen;
dataGrid.Rows[i].Cells[4].Value = timeTaken.Seconds.ToString() + "." + String.Format("{0:0.00000}", timeTaken.Milliseconds.ToString()) + " seconds.";
string sec = (DateTime.Now.Second < 10) ? "0" + DateTime.Now.Second.ToString() : DateTime.Now.Second.ToString();
string min = (DateTime.Now.Minute < 10) ? "0" + DateTime.Now.Minute.ToString() : DateTime.Now.Minute.ToString();
string hour = (DateTime.Now.Hour < 10) ? "0" + DateTime.Now.Hour.ToString() : DateTime.Now.Hour.ToString();
dataGrid.Rows[i].Cells[5].Value = hour + ":" + min + ":" + sec;
//loadbar
}
selectRows();
}
}
}
}
Checks a site:
/////////////////////////////////
////Check datagrid websites-button - returns response
/////////////////////////////////
private string[] checkSite(string url)
{
string[] response = new string[2];
url = dataGrid.Rows[0].Cells[2].Value.ToString();
if (url != null)
{
try
{
HttpWebRequest httpReq;
httpReq.Timeout = 10000;
//loadbar
dataGrid.Rows[0].DefaultCellStyle.BackColor = System.Drawing.Color.Wheat;
System.Diagnostics.Stopwatch timer = new System.Diagnostics.Stopwatch();
timer.Start();
HttpWebResponse httpRes = (HttpWebResponse)httpReq.GetResponse(); //httpRes.Close();
timer.Stop();
//loadbar
HttpStatusCode httpStatus = httpRes.StatusCode;
response[0] = httpStatus.ToString();
response[1] = timer.Elapsed.ToString();//*
httpRes.Close();
return response;
}
catch (Exception he)
{
response[0] = "catch";
response[1] = he.Message;
return response;
}
}
response[0] = "catch";
response[1] = "No URL entered";
return response;
//dataGrid.Rows[i].DefaultCellStyle.BackColor = System.Drawing.Color.Blue;
}
Thanks in advance.
Assuming the code provided is the actual code used:
First of all, your definition of 'False result' and 'Good result' is wrong. If you expect A but get B, that doesn't mean B is invalid. If your wife is giving birth and you expect a boy but it turns out the be a girl, its not a false result. Just unexpected.
That said: lets analyze your work: If it takes a long long time to check a site only to finally get a ??? result which isn't a 200 response code. We can almost savely assume you are dealing with a timeout. If your router, google or any fundamental network device in between is having problems, its expected to get an unexpected answer. "Timeout", "Bad Request", "Server not available" etc. Why would this happen? Its impossible to say for certain without having direct access to your environment.
Looking at your code however, i see that you're using the default TaskScheduler for making each check run as a task in the background (assuming you havent changed the default task scheduler which would be a vey bad practice to begin with). The default task scheduler, schedules each task on the threadpool which results in many many tasks running simultanious. Here we have a good candidate for overloading your network. Many sites (esspecially google) are kinda sensitive for handling many requests from the same source (esspecially if the frequency is high) so maybe google is blocking you temporarily or holding you back. Again, at this point it's pure speculation but the fact that you're running all checks simultaniously (unless the thread pool is on his max) is very likely the cause of your problem.
UPDATE
I would recommend working with a LimitedConcurrencyTaskScheduler ( see here: http://blogs.msdn.com/b/pfxteam/archive/2010/04/09/9990424.aspx ). Here you can limit the amount of tasks that can be run asynchronously. You have to do some testing for what number works ideally in your situation. Also make sure that the frequency is not 'too' high. Its hard to define what is too high, only testing can proof that.
In order to simulate your scenario, I have created a Winform with data grid and a button. On load of the form, I programmatically creates list of url’s (in a table) and bind to data grid. And on button click, we start the download process. In concise, the you have to write more defensive code and the following code only a skeleton of how you can fix the issue.
using System;
using System.Data;
using System.Net;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace app
{
public partial class Form1 : Form
{
DataTable urls = new DataTable();
public Form1()
{
InitializeComponent();
}
//Fill your uri's and bind to a data grid.
void InitTable()
{
//Silly logic to simulate your scenario.
urls = new DataTable();
urls.Columns.Add(new DataColumn("Srl", typeof(string)));
urls.Columns.Add(new DataColumn("Urls", typeof(Uri)));
urls.Columns.Add(new DataColumn("Result", typeof(string)));
DataRow dr = urls.NewRow();
dr["Srl"] = "1";
dr["Urls"] = new Uri("http://www.microsoft.com");
dr["Result"] = string.Empty;
urls.Rows.Add(dr);
dr = urls.NewRow();
dr["Srl"] = "2";
dr["Urls"] = new Uri("http://www.google.com");
dr["Result"] = string.Empty;
urls.Rows.Add(dr);
dr = urls.NewRow();
dr["Srl"] = "3";
dr["Urls"] = new Uri("http://www.stackoverflow.com");
dr["Result"] = string.Empty;
urls.Rows.Add(dr);
urls.AcceptChanges();
}
void UpdateResult()
{
dataGridView1.DataSource = urls;
}
//Important
// This example will freeze UI. You can avoid this while implementing
//background worker or pool with some event synchronization. I haven't covered those area since
//we are addressing different issue. Let me know if you would like to address UI freeze
//issue. Or can do it your self.
private void button1_Click(object sender, EventArgs e)
{
//Create array for Task to parallelize multiple download.
var tasks = new Task<string[]>[urls.Rows.Count];
//Initialize those task based on number of Uri's
for(int i=0;i<urls.Rows.Count;i++)
{
int index = i;//Do not change this. This is to avoid data race
//Assign responsibility and start task.
tasks[index] = new Task<string[]>(
() => checkSite(
new TaskInput(urls.Rows[index]["Urls"].ToString(), urls.Rows[index]["Srl"].ToString())));
tasks[index].Start();
}
//Wait for all task to complete. Check other overloaded if interested.
Task.WaitAll(tasks);
//block shows how to access result from task
foreach (var item in tasks)
{
DataRow[] rows=urls.Select("Srl='"+item.Result[2]+"'");
foreach (var row in rows)
row["Result"]=item.Result[0]+"|"+item.Result[1];
}
UpdateResult();
}
//This is dummy method which in your case 'Check Site'. You can have your own
string[] checkSite(TaskInput input)
{
string[] response = new string[3];
if (input != null)
{
try
{
WebResponse wResponse = WebRequest.Create(input.Url).GetResponse();
response[0] = wResponse.ContentLength.ToString();
response[1] = wResponse.ContentType;
response[2] = input.Srl;
return response;
}
catch (Exception he)
{
response[0] = "catch";
response[1] = he.Message;
response[2] = input.Srl;
return response;
}
}
response[0] = "catch";
response[1] = "No URL entered";
response[2] = input.Srl;
return response;
}
private void Form1_Load(object sender, EventArgs e)
{
InitTable();
UpdateResult();
}
}
//Supply custom object for simplicity
public class TaskInput
{
public TaskInput(){}
public TaskInput(string url, string srl)
{
Url = url;
Srl = srl;
}
public string Srl { get; set; }
public string Url { get; set; }
}
}

Categories

Resources