I am trying to call HttpClient request inside for loop as follows. It needs to do multiple consecutive calls to third party rest api.
But it only gives me fist service call result while loop exit before getting result from rest of the service call.
private void Search()
{
try
{
var i = 1;
using (var httpClient = new HttpClient())
{
while (i < 5)
{
string url = "https://jsonplaceholder.typicode.com/posts/" + i;
var response = httpClient.GetAsync(url).Result;
string jsonResult = response.Content.ReadAsStringAsync().Result;
Console.WriteLine(jsonResult.ToString());
i++;
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
When I run with debug points the program gives me all the result. But when I run it without debug points it gives me only the first result.
I tried this with using async, await methods too. It also gives me same result.
As I feel Program needs to wait until the async call returns data.
Please help me to solve this.
EDIT - async way
private async Task<string> SearchNew()
{
try
{
var i = 1;
var res = string.Empty;
using (var httpClient = new HttpClient())
{
while (i < 5)
{
string url = "https://jsonplaceholder.typicode.com/posts/" + i;
var response = httpClient.GetAsync(url).Result;
string jsonResult = await response.Content.ReadAsStringAsync();
res = res + jsonResult + " --- ";
i++;
}
}
return res;
}
catch (Exception ex)
{
return ex.Message;
}
}
Both are giving same result.
There's a few things here that you should be doing. First, move the HttpClient creation outside of your method and make it static. You only need one of them and having multiple can be really bad for stability (see here):
private static HttpClient _client = new HttpClient();
Next, extract the calls to the HttpClient into a single method, something simple like this:
//Please choose a better name than this
private async Task<string> GetData(string url)
{
var response = await _client.GetAsync(url);
return await response.Content.ReadAsStringAsync();
}
And finally, you create a list of tasks and wait for them all to complete asynchronously using Task.WhenAll:
private async Task<string[]> SearchAsync()
{
var i = 1;
var tasks = new List<Task<string>>();
//Create the tasks
while (i < 5)
{
string url = "https://jsonplaceholder.typicode.com/posts/" + i;
tasks.Add(GetData(url));
i++;
}
//Wait for the tasks to complete and return
return await Task.WhenAll(tasks);
}
And to call this method:
var results = await SearchAsync();
foreach (var result in results)
{
Console.WriteLine(result);
}
Related
I have a web page that I'm trying to call a web service and I'm having it skip out of the process when called.
Here's what I'm referring to...
When I call this method after the customer enters in their check information:
public CheckInfo SubmitCheck(CheckInfo checkInfo)
{
try
{
var check = new Check();
check.account_number = checkInfo.CheckAccountNumber;
check.transit_number = checkInfo.CheckRoutingNumber;
check.amount = checkInfo.Amount.ToString();
check.check_number = checkInfo.CheckNumber;
check.bill_to_city = checkInfo.City;
check.bill_to_country = "US";
check.bill_to_postal_code = checkInfo.Zip;
check.bill_to_street = checkInfo.Street;
check.bill_to_state = checkInfo.State;
check.name_on_check = checkInfo.NameOnCheck;
check.transaction_type = "sale";
check.account_type = checkInfo.AccountType;
check.check_type = checkInfo.CheckType;
var ent = new SuburbanPortalEntities();
var gatewaySettings = (from x in ent.GatewayUsers
where x.TokenId == CurrentCustomerSession.Current.TokenId &&
x.Gateway.Name == "DirectAch2"
select x).FirstOrDefault();
var credentials = new Authentication();
credentials.password = gatewaySettings.Password;
credentials.username = gatewaySettings.UserName;
var response = Process.SubmitCheck(credentials, check).Result;
The public class that calls the private class:
public static async Task<Response> SubmitCheck(Authentication authentication, Check check)
{
return await Submit(authentication, check, PaymentTypes.Check);
}
The SubmitCheck Method:
private static async Task<Response> Submit(Authentication authentication, Object payment, PaymentTypes paymentType)
{
var resp = new Response();
try
{
var client = new HttpClient();
var bodyjson = JsonConvert.SerializeObject(authentication);
var bodycontent = new StringContent(bodyjson, Encoding.UTF8, "application/json");
var authenticationPost =
await client.PostAsync("https://someplace.com/api/v2/Identity", bodycontent);
var bodyResponseJson = await authenticationPost.Content.ReadAsStringAsync();
When I get to this line, it just returns out of the method and it doesn't continue on with anything, it's like I never executed this method.
var authenticationPost =
await client.PostAsync("https://someplace.com/api/v2/Identity", bodycontent);
No other code is executed after this line. It just stops and the web page becomes available again. I have the method wrapped in a try catch but the catch isn't.. catching anything.
I'm at a loss at this poing, any suggestions?
EDIT#1
I wrapped the line in a try catch as suggested.
try
{
authenticationPost =
await client.PostAsync("https://someplace.com/api/v2/Identity", bodycontent);
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
It's stepping out of the try/catch and never executing any more code after that. No exception is caught, nothing, it just runs the line and leaves the method.
Here's your problem:
var response = Process.SubmitCheck(credentials, check).Result;
Don't block on async code, as I describe on my blog. This is a common mistake for those new to async/await. Instead of Result, use await:
public async Task<CheckInfo> SubmitCheck(CheckInfo checkInfo)
{
...
var response = await Process.SubmitCheck(credentials, check);
Note that you'd then need to await the call to SubmitCheck, and so on. It's async all the way.
Side note: I recommend using the standard pattern of *Async suffixes on your method names; it makes it clearer in the code that their return values need to be awaited:
public async Task<CheckInfo> SubmitCheckAsync(CheckInfo checkInfo)
{
...
var response = await Process.SubmitCheckAsync(credentials, check);
I wrote a web crawler and I want to know if my approach is correct. The only issue I'm facing is that it stops after some hours of crawling. No exception, it just stops.
1 - the private members and the constructor:
private const int CONCURRENT_CONNECTIONS = 5;
private readonly HttpClient _client;
private readonly string[] _services = new string[2] {
"https://example.com/items?id=ID_HERE",
"https://another_example.com/items?id=ID_HERE"
}
private readonly List<SemaphoreSlim> _semaphores;
public Crawler() {
ServicePointManager.DefaultConnectionLimit = CONCURRENT_CONNECTIONS;
_client = new HttpClient();
_semaphores = new List<SemaphoreSlim>();
foreach (var _ in _services) {
_semaphores.Add(new SemaphoreSlim(CONCURRENT_CONNECTIONS));
}
}
Single HttpClient instance.
The _services is just a string array that contains the URL, they are not the same domain.
I'm using semaphores (one per domain) since I read that it's not a good idea to use the network queue (I don't remember how it calls).
2 - The Run method, which is the one I will call to start crawling.
public async Run(List<int> ids) {
const int BATCH_COUNT = 1000;
var svcIndex = 0;
var tasks = new List<Task<string>>(BATCH_COUNT);
foreach (var itemId in ids) {
tasks.Add(DownloadItem(svcIndex, _services[svcIndex].Replace("ID_HERE", $"{itemId}")));
if (++svcIndex >= _services.Length) {
svcIndex = 0;
}
if (tasks.Count >= BATCH_COUNT) {
var results = await Task.WhenAll(tasks);
await SaveDownloadedData(results);
tasks.Clear();
}
}
if (tasks.Count > 0) {
var results = await Task.WhenAll(tasks);
await SaveDownloadedData(results);
tasks.Clear();
}
}
DownloadItem is an async function that actually makes the GET request, note that I'm not awaiting it here.
If the number of tasks reaches the BATCH_COUNT, I will await all to complete and save the results to file.
3 - The DownloadItem function.
private async Task<string> DownloadItem(int serviceIndex, string link) {
var needReleaseSemaphore = true;
var result = string.Empty;
try {
await _semaphores[serviceIndex].WaitAsync();
var r = await _client.GetStringAsync(link);
_semaphores[serviceIndex].Release();
needReleaseSemaphore = false;
// DUE TO JSON SIZE, I NEED TO REMOVE A VALUE (IT'S USELESS FOR ME)
var obj = JObject.Parse(r);
if (obj.ContainsKey("blah")) {
obj.Remove("blah");
}
result = obj.ToString(Formatting.None);
} catch {
result = string.Empty;
// SINCE I GOT AN EXCEPTION, I WILL 'LOCK' THIS SERVICE FOR 1 MINUTE.
// IF I RELEASED THIS SEMAPHORE, I WILL LOCK IT AGAIN FIRST.
if (!needReleaseSemaphore) {
await _semaphores[serviceIndex].WaitAsync();
needReleaseSemaphore = true;
}
await Task.Delay(60_000);
} finally {
// RELEASE THE SEMAPHORE, IF NEEDED.
if (needReleaseSemaphore) {
_semaphores[serviceIndex].Release();
}
}
return result;
}
4- The function that saves the result.
private async Task SaveDownloadedData(List<string> myData) {
using var fs = new FileStream("./output.dat", FileMode.Append);
foreach (var res in myData) {
var blob = Encoding.UTF8.GetBytes(res);
await fs.WriteAsync(BitConverter.GetBytes((uint)blob.Length));
await fs.WriteAsync(blob);
}
await fs.DisposeAsync();
}
5- Finally, the Main function.
static async Task Main(string[] args) {
var crawler = new Crawler();
var items = LoadItemIds();
await crawler.Run(items);
}
After all this, is my approach correct? I need to make millions of requests, will take some weeks/months to gather all data I need (due to the connection limit).
After 12 - 14 hours, it just stops and I need to manually restart the app (memory usage is ok, my VPS has 1 GB and it never used more than 60%).
static void Main(string[] args)
{
token objtoken = new token();
var location = AddLocations();
OutPutResults outPutResultsApi = new OutPutResults();
GCPcall gCPcall = new GCPcall();
OutPutResults finaloutPutResultsApi = new OutPutResults();
var addressdt = new AddressDataDetails();
finaloutPutResultsApi.addressDatas = new List<AddressDataDetails>();
Console.WriteLine("Hello World!");
List<string> placeId = new List<string>();
var baseUrl = "https://maps.googleapis.com/maps/api/place/textsearch/json?";
var apiKey = "&key=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx".Trim();
foreach (var itemlocations in location)
{
var searchtext = "query=" + itemlocations.Trim();
var finalUrl = baseUrl + searchtext + apiKey;
gCPcall.RecursiveApiCall(finalUrl, ref placeId, objtoken.NextToken);
}
var ids = gCPcall.myPalceid;
}
public List<string> RecursiveApiCall(string finalUrl, ref List<string> placeId, string nextToken = null)
{
try
{
var token = "&pagetoken=" + nextToken;
using (var client = new HttpClient())
{
var responseTask = client.GetAsync(finalUrl + token);
responseTask.Wait();
var result = responseTask.Result;
if (result.IsSuccessStatusCode)
{
var readTask = result.Content.ReadAsStringAsync();
readTask.Wait();
var students = readTask.Result;
Rootobject studentsmodel = JsonConvert.DeserializeObject<Rootobject>(students);
nextToken = studentsmodel.next_page_token;
foreach (var item in studentsmodel.results)
{
placeId.Add(item.place_id);
}
}
}
if (nextToken != null)
{
RecursiveApiCall(finalUrl, ref placeId, nextToken);
}
return placeId;
}
catch (Exception ex)
{
throw;
}
}
My recursive method has some issue. Here whenever I am debugging this code it work fine. It goes in recursive call twice.
As debugging result I am getting list place_id with 20 items in first call and next call 9 items total 29 items in place_id object which is correct in static main method.
But if I run without debugging mode I am getting only 20 place_id. next recursive iteration data is missing even if it has next valid token.
I don't have any clue why this is happening. Can someone tell me what is the issue with my code?
Here are my suggestions, which may or may not solve the problem:
// First of all, let's fix the signature : Go async _all the way_
//public List<string> RecursiveApiCall(string finalUrl, ref List<string> placeId, string nextToken = null)
// also reuse the HttpClient!
public async Task ApiCallAsync(HttpClient client, string finalUrl, List<string> placeId, string nextToken = null)
{
// Loop, don't recurse
while(!(nextToken is null)) // C# 9: while(nextToken is not null)
{
try
{
var token = "&pagetoken=" + nextToken;
// again async all the way
var result = await client.GetAsync(finalUrl+token);
if (result.IsSuccessStatusCode)
{
// async all the way!
var students = await result.Content.ReadAsStringAsync();
Rootobject studentsmodel = JsonConvert.DeserializeObject<Rootobject>(students);
nextToken = studentsmodel.next_page_token;
foreach (var item in studentsmodel.results)
{
// Will be reflected in main, so no need to return or `ref` keyword
placeId.Add(item.place_id);
}
}
// NO recursion needed!
// if (nextToken != null)
// {
// RecursiveApiCall(finalUrl, ref placeId, nextToken);
// }
}
catch (Exception ex)
{
// rethrow, only is somewhat useless
// I'd suggest using a logging framework and
// log.Error(ex, "Some useful message");
throw;
// OR remove try/catch here all together and wrap the call to this method
// in try / catch with logging.
}
}
Mind that you'll need to make your main :
async Task Main(string[] args)
and call this as
await ApiCallAsync(client, finalUrl, placeId, nextToken);
Also create an HttpClient in main and reuse that:
"HttpClient is intended to be instantiated once and re-used throughout the life of an application. Instantiating an HttpClient class for every request will exhaust the number of sockets available under heavy loads. This will result in SocketException errors." - Remarks
... which shouldn't do much harm here, but it's a "best practice" anyhow.
Now, as to why you get only 20 instead of expected 29 items, I cannot say if this resolves that issue. I'd highly recommend to introduce a Logging Framework and make log entries accordingly, so you may find the culprid.
I have the code :
public static async Task Download()
{
var urls = new[] {
"https://github.com/naudio/NAudio",
"https://twitter.com/mark_heath",
"https://github.com/markheath/azure-functions-links",
"https://pluralsight.com/authors/mark-heath",
"https://github.com/markheath/advent-of-code-js",
"http://stackoverflow.com/users/7532/mark-heath",
"https://mvp.microsoft.com/en-us/mvp/Mark%20%20Heath-5002551",
"https://github.com/markheath/func-todo-backend",
"https://github.com/markheath/typescript-tetris",};
var client = new HttpClient();
foreach (var url in urls)
{
var html = await client.GetStringAsync(url);
Console.WriteLine($"retrieved {html.Length} characters from {url}");
}
}
The all task client.GetStringAsync(url) will execute as the same time. But I wanna call client.GetStringAsync each url after timeout (no need to await the previous task complete). Ex :
at 00:00:01 - GetStringAsync url1
at 00:00:05 - GetStringAsync url2
at 00:00:09 - GetStringAsync url3
Each task will be started after 4 seconds. So how can I do that? Thanks
If you don't want to await the querying of the url, then don't await it. If you want to run the continuation after 4 seconds (or any other fixed period of time), then use Task.Delay.
public static async Task Download()
{
var urls = new[] {
"https://github.com/naudio/NAudio",
"https://twitter.com/mark_heath",
"https://github.com/markheath/azure-functions-links",
"https://pluralsight.com/authors/mark-heath",
"https://github.com/markheath/advent-of-code-js",
"http://stackoverflow.com/users/7532/mark-heath",
"https://mvp.microsoft.com/en-us/mvp/Mark%20%20Heath-5002551",
"https://github.com/markheath/func-todo-backend",
"https://github.com/markheath/typescript-tetris",};
var client = new HttpClient();
foreach (var url in urls)
{
ProcessURL(url);
await Task.Delay(TimeSpan.FromSeconds(4));
}
async Task ProcessURL(string url)
{
try
{
var html = await client.GetStringAsync(url);
Console.WriteLine($"retrieved {html.Length} characters from {url}");
}
catch (Exception e)
{
//TODO handle any errors in processing the URL
}
}
}
Note that since nothing is awaiting ProcessURL, it'll need to be responsible for handling any errors that might happen internally, since no caller will be able to handle them.
Do you mean you want to wait 4 seconds between tech call, instead of waiting for the previous call to complete?
You can use Task.Delay for that -
public static async Task Download()
{
var urls = new[] {
"https://github.com/naudio/NAudio",
"https://twitter.com/mark_heath",
"https://github.com/markheath/azure-functions-links",
"https://pluralsight.com/authors/mark-heath",
"https://github.com/markheath/advent-of-code-js",
"http://stackoverflow.com/users/7532/mark-heath",
"https://mvp.microsoft.com/en-us/mvp/Mark%20%20Heath-5002551",
"https://github.com/markheath/func-todo-backend",
"https://github.com/markheath/typescript-tetris",};
var client = new HttpClient();
foreach (var url in urls)
{
var waitingTask = Task.Delay(1000 * 4); //4000 milliseconds
var fireAndForget = client.GetStringAsync(url);
await waitingTask;
}
}
A couple of things to notice here -
If sending the HTTP call takes
more than 4 seconds, your code will be delayed for the amount of
time it takes to send it out, even if it's more than 4 seconds.
By
not waiting for the HTTP call to complete, you can't use the
resulting HTML
You can solve this issue with something like a continuation -
client.GetStringAsync(url).ContinueWith(task => Console.WriteLine($"retrieved {task.Result.Length} characters from {url}"));
Edit - adding for completeness as per #Servy's comment -
My continuation example above is very partial, and meant to convey the idea of handling the result of a task that was not awaited. There are multiple ways to handle the the download process, both in terms of using the result and of handling errors. Here is an approach that uses ContinueWith, but checks to see how the download completed instead of assuming is succeeded -
var task = client.GetStringAsync(url);
task.ContinueWith(task =>
{
// task completed correctly, do something with the result, like -
Console.WriteLine($"retrieved {task.Result.Length} characters from {url}");
}, TaskContinuationOptions.OnlyOnRanToCompletion);
task.ContinueWith(task =>
{
// task did not complete successfully, you can check why using the task iteslf, for example
if (task.IsFaulted)
{
// the task failed with an unhandled exception, you can access the exception instance if you want, for example -
Console.WriteLine($"Error while downloading from {url} - {task.Exception}");
}
}, TaskContinuationOptions.NotOnRanToCompletion);
Use Task.Delay Check
and wait 4 secands between each call
HttpClientHelper: HTTPrequest Wrapper
HttpResult: wrap request result
public static async Task Download()
{
HttpClientHelper clientHelper = new HttpClientHelper();
List<HttpResult> httpResults = new List<HttpResult>();
var urls = new[] {
"https://github.com/naudio/NAudio",
"https://twitter.com/mark_heath",
"https://github.com/markheath/azure-functions-links",
"https://pluralsight.com/authors/mark-heath",
"https://github.com/markheath/advent-of-code-js",
"https://stackoverflow.com/users/7532/mark-heath",
"https://mvp.microsoft.com/en-us/mvp/Mark%20%20Heath-5002551",
"https://github.com/markheath/func-todo-backend",
"https://github.com/markheath/typescript-tetris",};
foreach (var url in urls)
{
HttpResult httpResult = clientHelper.GetStringAsync(url);
httpResults.Add(httpResult);
if (httpResult.HasError)
{
Console.WriteLine($"Error occurred: '{httpResult.Error}' on characters from {url}");
}
else
{
Console.WriteLine($"retrieved {httpResult.Result.Length} characters from {url}");
}
await Task.Delay(5000);
}
}
public class HttpClientHelper
{
public async Task<HttpResult> GetStringAsync(string url)
{
HttpResult httpResult = new HttpResult
{
URL = url
};
try
{
HttpClient client = new HttpClient();
httpResult.Result = await client.GetStringAsync(url);
}
catch (Exception e)
{
//todo:handel Exception
httpResult.HasError = true;
httpResult.Error = e.Message + Environment.NewLine + e.InnerException?.Message;
}
return httpResult;
}
}
public class HttpResult
{
public string URL { get; set; }
public bool HasError { get; set; }
public string Error { get; set; }
public string Result { get; set; }
}
I am trying to make lots of calls from my server to a REST API that is exposed by another server but the code is taking too long to run.
Below is the code which takes a lot of time. Right now I am using C# Async/Await along with HTTPClient, is there a better way I can do this?
static async Task RunAsync()
{
HttpClient client = new HttpClient();
client.BaseAddress = new Uri(URL);
foreach (var workbk in (workbooksforuserresultingMessage.Items[1] as workbookListType).workbook)
{
if (workbk.project.name == "Ascend")
{
tsResponse viewresultingMessage = null;
//Get View Data
HttpRequestMessage viewrequestMessage = new HttpRequestMessage(HttpMethod.Get, "sites/" + ((siteresultingMessage.Items[0] as siteType).id.ToString()) + "/workbooks/" + workbk.id + "/views");
// Add our custom headers
viewrequestMessage.Headers.Add("X-Tableau-Auth", (resultingMessage.Items[0] as credentialsType).token.ToString());
HttpResponseMessage viewrequestMessageresponse = await client.SendAsync(viewrequestMessage);
if (viewrequestMessageresponse.IsSuccessStatusCode)
{
var viewresponsecontent = await viewrequestMessageresponse.Content.ReadAsStringAsync();
XmlSerializer siteserializer = new XmlSerializer(typeof(tsResponse));
using (TextReader reader = new StringReader(viewresponsecontent))
{
viewresultingMessage = (tsResponse)siteserializer.Deserialize(reader);
}
}
}
}
foreach (var workbk in (workbooksforuserresultingMessage.Items[1] as workbookListType).workbook)
{
if (workbk.project.name == "Ascend")
{
foreach (var vu in workbk.views)
{
tsResponse viewImageresultingMessage = null;
//Get View Data
HttpRequestMessage viewImagerequestMessage = new HttpRequestMessage(HttpMethod.Get, "sites/" + ((siteresultingMessage.Items[0] as siteType).id.ToString()) + "/workbooks/" + workbk.id + "/views/" + vu.id + "/previewImage");
// Add our custom headers
viewImagerequestMessage.Headers.Add("X-Tableau-Auth", (resultingMessage.Items[0] as credentialsType).token.ToString());
HttpResponseMessage viewImagewrequestMessageresponse = await client.SendAsync(viewImagerequestMessage);
if (viewImagewrequestMessageresponse.IsSuccessStatusCode)
{
var viewImageresponsecontent = await viewImagewrequestMessageresponse.Content.ReadAsByteArrayAsync();
XmlSerializer siteserializer = new XmlSerializer(typeof(tsResponse));
using (var ms = new MemoryStream(viewImageresponsecontent))
{
Image returnImage = Image.FromStream(ms);
//return returnImage;
}
}
}
}
}
}
Those 'await's inside your loop will serialize the requests. Consider instead using .ContinueWith on the task to do some work with the result, keep track of the tasks in an array, then call Task.WhenAll once you're done setting up all the parallel work.
AS #TheESJ said the awaits make your code execute in a serial fashion. That is once execution reaches the first await, execution is effectively "paused" and will not resume until that Task is complete. You can avoid this by not awaiting the Task, just add it to a list of tasks to keep track of.
To facilitate this I think it will help if you introduced a couple of helper methods to execute the body of your loops and return a Task.
public Task<tsResponse> GetViewString(HttpRequestMessage viewrequestMessage)
{
tsResponse viewresultingMessage = null;
HttpResponseMessage viewrequestMessageresponse = await client.SendAsync(viewrequestMessage);
if (viewrequestMessageresponse.IsSuccessStatusCode)
{
var viewresponsecontent = await viewrequestMessageresponse.Content.ReadAsStringAsync();
XmlSerializer siteserializer = new XmlSerializer(typeof(tsResponse));
using (TextReader reader = new StringReader(viewresponsecontent))
{
viewresultingMessage = (tsResponse)siteserializer.Deserialize(reader);
}
}
return viewresultingMessage;
}
public Task<tsResponse> GetViewImage(HttpRequestMessage viewImagerequestMessage)
{
tsResponse viewImageresultingMessage = null;
//Get View Data
HttpResponseMessage viewImagewrequestMessageresponse = await client.SendAsync(viewImagerequestMessage);
if (viewImagewrequestMessageresponse.IsSuccessStatusCode)
{
var viewImageresponsecontent = await viewImagewrequestMessageresponse.Content.ReadAsByteArrayAsync();
XmlSerializer siteserializer = new XmlSerializer(typeof(tsResponse));
using (var ms = new MemoryStream(viewImageresponsecontent))
{
return Image.FromStream(ms);
}
}
}
Then in your main loop you just add the tasks to a list as the methods are kicked off, this will essentially execute the tasks in parallel. You may need to increase the number of concurrent connections your server can make if it causes a problem. Your main method then becomes.
static async Task RunAsync()
{
HttpClient client = new HttpClient();
client.BaseAddress = new Uri(URL);
var tasks = new List<Task<tsResponse>>();
foreach (var workbk in (workbooksforuserresultingMessage.Items[1] as workbookListType).workbook)
{
if (workbk.project.name == "Ascend")
{
tsResponse viewresultingMessage = null;
//Get View Data
HttpRequestMessage viewrequestMessage = new HttpRequestMessage(HttpMethod.Get, "sites/" + ((siteresultingMessage.Items[0] as siteType).id.ToString()) + "/workbooks/" + workbk.id + "/views");
// Add our custom headers
viewrequestMessage.Headers.Add("X-Tableau-Auth", (resultingMessage.Items[0] as credentialsType).token.ToString());
tasks.Add(GetViewString(viewrequestMessage);
}
}
foreach (var workbk in (workbooksforuserresultingMessage.Items[1] as workbookListType).workbook)
{
if (workbk.project.name == "Ascend")
{
foreach (var vu in workbk.views)
{
tsResponse viewImageresultingMessage = null;
//Get View Data
HttpRequestMessage viewImagerequestMessage = new HttpRequestMessage(HttpMethod.Get, "sites/" + ((siteresultingMessage.Items[0] as siteType).id.ToString()) + "/workbooks/" + workbk.id + "/views/" + vu.id + "/previewImage");
// Add our custom headers
viewImagerequestMessage.Headers.Add("X-Tableau-Auth", (resultingMessage.Items[0] as credentialsType).token.ToString());
tasks.Add(GetViewImage(viewImagerequestMessage);
}
}
}
// wait for all the tasks to complete (non blocking)
await Task.WhenAll(tasks);
}