I have made two functions in a WCF service and call them in silverlight using asynchronization. I call one method after the other, but before completion of the first method, silverlight executes the second method. I want the first method to completely finish executing before the second method call.
thanks for your reply i m pasting my code please suggest in code how i implement.
private GDOperations.GDDoneOperationsClient _gdDoneOperation;
private ImageOperationsClient proxy = null;
foreach (var file in _filesCollection)
{
clsImageTransactionEntity _clsImageEntity = new clsImageTransactionEntity();
_clsImageEntity.ImageByte = GetFileData(file.OpenRead());
_clsImageEntity.ImageExtension = file.Extension;
_clsImageEntity.ImageName = file.Name;
_clsImageEntity.ImageType = 2;
_clsImageEntity.ImagePath = "~/CMSImages/FinalImages/" + lblSelectedBarcode.Content.ToString() + "/" + file.Name;
_clsImageEntity.JabongBarcode = lblSelectedBarcode.Content.ToString();
GDOperations.clsImageTransactionEntity _clsImageGDEntity = new GDOperations.clsImageTransactionEntity();
_clsImageGDEntity.ImageExtension = file.Extension;
_clsImageGDEntity.ImageName = file.Name;
_clsImageGDEntity.ImageType = 2;
_clsImageGDEntity.ImagePath = "~/CMSImages/FinalImages/" + lblSelectedBarcode.Content.ToString() + "/" + file.Name;
_clsImageGDEntity.JabongBarcode = lblSelectedBarcode.Content.ToString();
_clsImageGDEntity.RoleId = roleID;
_clsImageGDEntity.TaskID = taskID;
_clsImageGDEntity.UserID = UserId;
_clsImageGDEntity.SystemIP = systemIP;
_clsGdAllotment.clsImageTransactionEntity.Add(_clsImageGDEntity);
----- first method calling-----
proxy.UploadFinalImageCompleted += (s, e) =>
{
if (e.Error == null)
{
}
};
proxy.UploadFinalImageAsync(_clsImageEntity);
countfile = countfile + 1;
pbUploadFiles.Value = countfile;
}
_clsGdAllotment.GdID = int.Parse(lblUserID.Content.ToString());
_clsGdAllotment.JabongBarcode = lblSelectedBarcode.Content.ToString();
_clsGdAllotment.TaskID = taskID;
--- after for loop completion calling second method -----
_gdDoneOperation.InsertGDDoneInformationCompleted += _gdDoneOperation_InsertGDDoneInformationCompleted;
_gdDoneOperation.InsertGDDoneInformationAsync(_clsGdAllotment);`
Please help its urgent.
If you're using Task-Based Async Pattern:
var task1 = CallFirstAsyncMethod();
task1.Wait(); // waiting task to finish
var task2 = CallAnotherAsyncMethod();
// or subscribe to the task continuation to call second
// method when first operation will finished
task1.ContinueWith(t =>
{
// add error handling
var task2 = CallAnotherAsyncMethod();
});
If you're using Classical Async Pattern (a.k.a. APM):
IAsyncResult ar1 = CallFirstAsyncMethod();
ar1.WaitHandle.Wait();
IAsyncResult ar2 = CallSecondAsyncMethod();
// or use the same technique asynchronously
CallFirstAsyncMethod(ar => // Suppose we should provide appropriate callback
{
// Call to appropriate EndInvoke method
IAsyncResult ar2 = CallSecondAsyncMethod();
}, state);
You can call the second in the callback of the first, no ?
Or is Visual Studio < 2012
You can use AutoResetEvent :
MyServiceClient clientService;
AutoResetEvent autoResetEvent = new AutoResetEvent(false);
public void Execute()
{
InvokeCompletedEventArgs data = null;
clientService.InvokeCompleted += (e, f) =>
{
data = f;
autoResetEvent.Set();
};
m_proxy.MyCallAync();
autoResetEvent.WaitOne(); // Wait the set of autoResetEvent
m_proxy.MySecondCallAync(data); // Data return by the first call
}
Antoine
Related
I want to run a function over all rows, but instead of it running for each row at a time, I want it to run in parallel. The issue is that it seems to only run twice (while there are 217 products on the list) and it seems rows are picked randomly. I'm not sure why it's happening - the synchronous version works as intended.
The function makes an API call to a SOAP service that uses row data from WPF SfDataGrid. Maybe the API closes connection after so many requests? It's really hard to tell and I don't know how I could check it besides writing a ticket and waiting a week.
A part of event from which the function is called:
var tasks = new List<Task>();
using (var db = new SqliteConnection("Data Source=file:products.sqlite"))
{
using (var client = new ApiOrdersPortTypeClient(binding, address))
{
db.Open();
// run ScanProduct() on each row in a WPF SfDataGrid
foreach (var row in ProductList.View.Records)
{
tasks.Add(Task.Factory.StartNew(
() => ScanProduct(row, desiredDays, deliveryTime, client, db)));
}
Task.WaitAll(tasks.ToArray());
}
}
ScanProduct():
private async Task ScanProduct(RecordEntry row, int desiredDays, int deliveryTime, ApiOrdersPortTypeClient client, SqliteConnection db)
{
await db.OpenAsync();
var selectedItem = (Product)row.Data;
if (selectedItem.IsIgnored == true | selectedItem.IsInDelivery == true)
{
return;
}
else
{
var pagesCount = await ApiRequests
.GetOrdersPages(int.Parse(selectedItem.Id), desiredDays, client);
var listSold = await ApiRequests
.GetOrdersFromApi(int.Parse(selectedItem.Id), desiredDays, pagesCount);
foat x = 100.0; // cut irrelevant stuff
if (x > selectedItem.Stock)
{
using (var command =
new SqliteCommand($"UPDATE products_settings SET requires_purchase = 1,"
+ $" was_checked_with = {desiredDays},"
+ $"sold_amount = {listSold.Count},"
+ $"average_daily = '{averageSales.ToString()}',"
+ $"average_delivery = '{x}'"
+ $"WHERE id = {selectedItem.Id};", db))
{
await db.OpenAsync();
command.ExecuteReader();
}
}
else
{
using (var command2 =
new SqliteCommand($"UPDATE products_settings SET requires_purchase = 0,"
+ $"was_checked_with = {desiredDays},"
+ $"sold_amount = {listSold.Count},"
+ $"average_daily = '{averageSales.ToString()}',"
+ $"average_delivery = '{x}"
+ $"WHERE id = {selectedItem.Id};", db))
{
await db.OpenAsync();
command2.ExecuteReader();
}
}
}
}
Your issue is here:
tasks.Add(Task.Factory.StartNew(() => ScanProduct(row, desiredDays, deliveryTime, client, db)));
ScanProduct is an asynchronous function, and thus needs to be awaited.
Each call to Task.Factory.StartNew returns a Task, which will be awaited using Task.WaitAll, however, within each task, a call to ScanProduct will return another Task, which is not being awaited by Task.WaitAll.
The solution is to use an async lambda in combination with Task.Run, then in each case, the outer Task will not complete until ScanProduct has also completed.
tasks.Add(Task.Run(async () => await ScanProduct(row, desiredDays, deliveryTime, client, db)));
I have a method to generate software activation key from User Information:
private async void GenerateAsync()
{
await Task.Run(() =>
{
var secretstring = "CustomerName >> " + txtFullname.Text + " >> " + txtproducid.Text;
keymng = new KeyManager(secretstring);
var dateexp = numExpdate.Value;
if (dateexp == 0)
{
dateexp = 730000;
}
if (cbLicenseType.SelectedIndex == 0)
{
kvc = new KeyValueClass()
{
LicenseType = LicenseType.FULL,
Header = Convert.ToByte(9),
Footer = Convert.ToByte(6),
ProductCode = PRODUCTCODE,
Edition = (Edition)Enum.Parse(typeof(Edition), cbEdition.SelectedText),
Version = 1,
Expiration = DateTime.Now.AddDays(Convert.ToInt32(dateexp))
};
if (!keymng.GenerateKey(kvc, ref productkey))
{
//Handling Error
}
}
else
{
kvc = new KeyValueClass()
{
LicenseType = LicenseType.TRIAL,
Header = Convert.ToByte(9),
Footer = Convert.ToByte(6),
ProductCode = PRODUCTCODE,
Edition = (Edition)Enum.Parse(typeof(Edition), cbEdition.SelectedText),
Version = 1,
Expiration = DateTime.Now.AddDays(Convert.ToInt32(dateexp))
};
if (!keymng.GenerateKey(kvc, ref productkey))
{
//Handling Error
}
}
});
}
and I have progressbar. I want to run this method async and update progress to progressbar. How to update UI with async-await method. BackgroundWorker is alternative???
You should use the more modern IProgress<T>/Progress<T> types:
var progress = new Progress<int>(value => { progressBar.Value = value; });
await Task.Run(() => GenerateAsync(progress));
void GenerateAsync(IProgress<int> progress)
{
...
progress?.Report(13);
...
}
This is better than Invoke because it doesn't tie your business logic (GenerateAsync) to a particular UI, or to any UI at all.
I use this method in Winforms:
progressBar1.Invoke((Action)(() => progressBar1.Value=50))
I am trying to make create a function to get the source code from a number of pages. After each page is grabbed, I want to update a label on my form indicating the progress (1 of 5, 2 of 5, etc.).
However, no matter what I try, the GUI completely freezes until the for loop has ended.
public List<List<string>> GetPages(string base_url, int num_pages)
{
var pages = new List<List<string>>();
var webGet = new HtmlWeb();
var task = Task.Factory.StartNew(() => {
for (int i = 0; i <= num_pages; i++)
{
UpdateMessage("Fetching page " + i + " of " + num_pages + ".");
var page = new List<string>();
var page_source = webGet.Load(url+i);
// (...)
page.Add(url+i);
page.Add(source);
pages.Add(page);
}
});
task.Wait();
return pages;
}
The call to this method looks like this:
List<List<string>> pages = site.GetPages(url, num_pages);
If I remove task.Wait(); the GUI unfreezes, the label updates properly, but the code continues without the needed multidimensional list.
I should say that I'm very new to C#. What the heck am I doing wrong?
Update
As per Darin, I have changed my method:
public async Task<List<List<string>>> GetPages(string url, int num_pages)
{
var pages = new List<List<string>>();
var webGet = new HtmlWeb();
for (int i = 0; i <= num_pages; i++)
{
UpdateMessage("Fetching page " + i + " of " + num_pages + ".");
var page = new List<string>();
var page_source = webGet.Load(url+i);
// (...)
page.Add(url+i);
page.Add(source);
pages.Add(page);
}
return pages;
}
And the call:
List<List<string>> pages = await site.GetPages(url, num_pages);
However, now I am getting this error:
The 'await' operator can only be used within an async method. Consider marking this method with the 'async' modifier and changing its return type to 'Task'.
But when I mark the method with async, the GUI still freezes.
Update 2
Woops! I seem to missed a piece of Darin's new method. I have now included await webGet.LoadAsync(url + i); in the method. I have also marked the method I am calling from as async.
Now, unfortunately, I'm getting this error:
'HtmlWeb' does not contain a definition for 'LoadAsync' and no extension method 'LoadAsync' accepting a first argument of type 'HtmlWeb' could be found (are you missing a using directive or an assembly reference?)
I've checked, I'm using .NET 4.5.2, and the HtmlAgilityPack in my References is the Net45 version. I have no idea what's going on now.
If I remove task.Wait(); the GUI unfreezes, the label updates
properly, but the code continues without the needed multidimensional
list.
That's normal. You should update your function so that it doesn't return the value but rather the task:
public Task<List<List<string>>> GetPages(string base_url, int num_pages)
{
var webGet = new HtmlWeb();
var task = Task.Factory.StartNew(() =>
{
var pages = new List<List<string>>();
for (int i = 0; i <= num_pages; i++)
{
UpdateMessage("Fetching page " + i + " of " + num_chapters + ".");
var page = new List<string>();
var page_source = webGet.Load(url+i);
// (...)
page.Add(url+i);
page.Add(source);
pages.Add(page);
}
return pages;
});
return task;
}
and then when calling this function you will use the ContinueWith on the result:
var task = GetPages(baseUrl, numPages);
task.ContinueWith(t =>
{
List<List<string>> chapters = t.Result;
// Do something with the results here
});
Obviously before accessing t.Result in the continuation you probably would like to first check the other properties to see if the task completed successfully or if some exception was thrown so that you can act accordingly.
Also if you are using .NET 4.5 you may consider taking advantage of the async/await constructs:
public async Task<List<List<string>>> GetPages(string base_url, int num_pages)
{
var webGet = new HtmlWeb();
var pages = new List<List<string>>();
for (int i = 0; i <= num_pages; i++)
{
UpdateMessage("Fetching page " + i + " of " + num_chapters + ".");
var page = new List<string>();
var page_source = await webGet.LoadAsync(url+i);
// (...)
page.Add(url+i);
page.Add(source);
pages.Add(page);
}
return pages;
}
and then:
List<List<string>> chapters = await GetPages(baseUrl, numPages);
// Do something with the results here.
Assuming WinForms, start by making the toplevel eventhandler async void .
You then have an async method that can await a Task<List<List<string>>> method. That method does not have to be async itself.
private async void Button1_Click(...)
{
var pages = await GetPages(...);
// update the UI here
}
public Task<List<List<string>>> GetPages(string url, int num_pages)
{
...
return task;
}
I'll start off by publishing the code that is troubled:
public async Task main()
{
Task t = func();
await t;
list.ItemsSource = jlist; //jlist previously defined
}
public async Task func()
{
TwitterService service = new TwitterService(_consumerKey, _consumerSecret);
service.AuthenticateWith(_accessToken, _accessTokenSecret);
TwitterGeoLocationSearch g = new TwitterGeoLocationSearch(40.758367, -73.982706, 25, 0);
SearchOptions s = new SearchOptions();
s.Geocode = g;
s.Q = "";
s.Count = 1;
service.Search(s, (statuses, response) => get_tweets(statuses, response));
void get_tweets(TwitterSearchResult statuses, TwitterResponse response)
{
//unimportant code
jlist.Add(info);
System.Diagnostics.Debug.WriteLine("done with get_tweets, jlist created");
}
I am having issues with the get_tweets(..) function running (on what I believe a different thread) and the Task t is not awaited like I have in the main function. Basically, my issue is that the list.Itemsource = jlist is ran before the get_tweets function is finished. Does anyone have a solution or the right direction to point me in?
First, create a TAP wrapper for TwitterService.Search, using TaskCompletionSource. So something like:
public static Task<Tuple<TwitterSearchResult, TwitterResponse>> SearchAsync(this TwitterService service, SearchOptions options)
{
var tcs = new TaskCompletionSource<Tuple<TwitterSearchResult, TwitterResponse>>();
service.Search(options, (status, response) => tcs.SetResult(Tuple.Create(status, response)));
return tcs.Task;
}
Then you can consume it using await:
SearchOptions s = new SearchOptions();
s.Geocode = g;
s.Q = "";
s.Count = 1;
var result = await service.SearchAsync(s);
get_tweets(result.Item1, result.Item2);
I have two classes
Parser.cs:
....
client.DownloadStringCompleted += (sender, e) =>
{
Result = JsonConvert.DeserializeObject<Flight>(e.Result);
};
client.DownloadStringAsync(new Uri(uri));
and Main.cs:
...
var p = new Parser();
p.Parse();
someMethod(p.Result);
How can i run someMethod when DownloadStringAsync from Parser.cs is done?
This is accomplished by using the Task Parallel Library
You can change your Parse method to:
Task<string> ParseAsync()
{
return client.DownloadStringTaskAsync(new Uri(uri));
}
Then your Main method:
var p = new Parser();
var parseTask = p.Parse();
//This will block the current thread until Result is available
someMethod(parseTask.Result);
or if you don't want to block current thread, you can use continuation:
var p = new Parser();
var parseTask = p.Parse();
parseTask.ContinueWith(task => someMethod(task.Result));
All this is assuming .Net 4.5.