How can I use nested Async (WCF) calls within foreach loops in Silverlight? - wcf

The following code contains a few nested async calls within some foreach loops. I know the silverlight/wcf calls are called asyncrously -but how can I ensure that my wcfPhotographers, wcfCategories and wcfCategories objects are ready before the foreach loop start? I'm sure I am going about this all the wrong way -and would appreciate an help you could give.
private void PopulateControl()
{
List<CustomPhotographer> PhotographerList = new List<CustomPhotographer>();
proxy.GetPhotographerNamesCompleted += proxy_GetPhotographerNamesCompleted;
proxy.GetPhotographerNamesAsync();
//for each photographer
foreach (var eachPhotographer in wcfPhotographers)
{
CustomPhotographer thisPhotographer = new CustomPhotographer();
thisPhotographer.PhotographerName = eachPhotographer.ContactName;
thisPhotographer.PhotographerId = eachPhotographer.PhotographerID;
thisPhotographer.Categories = new List<CustomCategory>();
proxy.GetCategoryNamesFilteredByPhotographerCompleted += proxy_GetCategoryNamesFilteredByPhotographerCompleted;
proxy.GetCategoryNamesFilteredByPhotographerAsync(thisPhotographer.PhotographerId);
// for each category
foreach (var eachCatergory in wcfCategories)
{
CustomCategory thisCategory = new CustomCategory();
thisCategory.CategoryName = eachCatergory.CategoryName;
thisCategory.CategoryId = eachCatergory.CategoryID;
thisCategory.SubCategories = new List<CustomSubCategory>();
proxy.GetSubCategoryNamesFilteredByCategoryCompleted += proxy_GetSubCategoryNamesFilteredByCategoryCompleted;
proxy.GetSubCategoryNamesFilteredByCategoryAsync(thisPhotographer.PhotographerId,thisCategory.CategoryId);
// for each subcategory
foreach(var eachSubCatergory in wcfSubCategories)
{
CustomSubCategory thisSubCatergory = new CustomSubCategory();
thisSubCatergory.SubCategoryName = eachSubCatergory.SubCategoryName;
thisSubCatergory.SubCategoryId = eachSubCatergory.SubCategoryID;
}
thisPhotographer.Categories.Add(thisCategory);
}
PhotographerList.Add(thisPhotographer);
}
PhotographerNames.ItemsSource = PhotographerList;
}
void proxy_GetPhotographerNamesCompleted(object sender, GetPhotographerNamesCompletedEventArgs e)
{
wcfPhotographers = e.Result.ToList();
}
void proxy_GetCategoryNamesFilteredByPhotographerCompleted(object sender, GetCategoryNamesFilteredByPhotographerCompletedEventArgs e)
{
wcfCategories = e.Result.ToList();
}
void proxy_GetSubCategoryNamesFilteredByCategoryCompleted(object sender, GetSubCategoryNamesFilteredByCategoryCompletedEventArgs e)
{
wcfSubCategories = e.Result.ToList();
}

Yes, before you can proceed with the next step of the algorithm, you need to have gotten the result of the previous step, which can be hard when you have to use the async methods.
If this is not happening on the UI thread, then you could just block and wait for the response. For example, have each "completed" method signal (using whatever synchronization primitives are available in Silverlight; I don't know offhand e.g. if ManualResetEvent is there, if so, have the completed callback call .Set()), and then have your main PopulateControl method invoke the FooAsync() call and then block until the ManualResetEvent signals (by calling .Wait()).
If this is on the UI thread and you really need to write a non-blocking solution, then it is much, much harder to code this up correctly in C#. You might consider using F# instead, where asyncs provide a nice programming model for non-blocking calls.
EDIT:
Pseudo-code example to block for results:
// class-level
ManualResetEvent mre = new ManualResetEvent(false);
// some method that needs to make WCF call and use results
void Blah() {
// yadda yadda
proxy.FooCompleted += (o,ea) => { ... mre.Set(); };
proxy.FooAsync(...);
mre.WaitOne(); // block until FooCompleted
// use results from FooCompleted now that they're here
// mre.Reset() if you intend to use it again later
}
I used a lambda for FooCompleted, but using a separate method like you have is fine too.

Alternatively, for each async method you are using to populate the collection you can create a helper method that would return IObservable and then use Linq query to group the result.
E.g.:
private IObservable<Photographer> GetPhotographerNames()
{
var photographers = Observable
.FromEvent<GetPhotographerNamesCompletedEventArgs>(proxy, "GetPhotographerNamesCompleted")
.Prune()
.SelectMany(e => e.EventArgs.Result.ToObservable());
proxy.GetPhotographerNamesAsync();
return photographers;
}
And similarly:
private IObservable<Category> GetCategoryNamesFilteredByPhotographer(int photographerId) { ... }
private IObservable<SubCategory> GetSubCategoryNamesFilteredByCategory(int photographerId, int categoryId) { ... }
Now you can write a Linq query:
var pcs = from p in GetPhotographerNames()
from c in GetCategoryNamesFilteredByPhotographer(p.PhotographerId)
from s in GetSubCategoryNamesFilteredByCategory(p.PhotographerId, c.CategoryId)
select new {p, c, s};
This query will return you a list of triplets (Photographer, Category, SubCategory) Now all you have to do is to Subscribe to it and aggregate it to the objects you use on the client which should be pretty straightforward.

Related

How to run a simulation case using CaseRunner function?

I'm currently working on a Petrel plug-in in which I need to run a simulation case (through a "For Loop"), I create my case runner, export it and the run it...but after finishing the simulation and closing the console, I check the CaseRunner.IsRunning property and it shows true! This cause that the results have not been loaded to the petrel system.
I tried to load the results manually after finishing the Run of my case (using caserunner and also using a batch file in my code) and I can't see any results in the programming environment.
Does anybody have a solution for this situation?
This is the related part of my code:
Case theCase = arguments.TheCase;
Case Test2 = simroots.CreateCase(theCase, "FinalCase");
CaseRunner cRunners = SimulationSystem.GetCaseRunner(Test2);
cRunners.Export();
cRunners.Run();
bool b = cRunners.IsRunning;
actually I checked when the process finishes; after "cRunners.Run" the code waits for exit the process using:
System.Diagnostics.Process[] parray = System.Diagnostics.Process.GetProcesses();
foreach (System.Diagnostics.Process pr in parray)
{
if (pr.ProcessName == "cmd")
{
pr.WaitForExit();//just wait
}
}
and when the console closes itself, i checked the cRunners.IsRunning term.
However, I'm not so expert... can you show me an example of using CaseRunnerMonitor? both definition of the derived class and its implementation.
All I need is running a simulation case n times via a for loop and
after each Run access to its provided summary results.
I tried some different scenarios to get my desired results, I put here some of them
First I create my CaseRunnerMonitor class:
public class MyMonitor : CaseRunnerMonitor
{
//…
public override void RunCompleted()
{
// define arguments
foreach (Slb.Ocean.Petrel.DomainObject.Simulation.SummaryResult sr in simroot.SummaryResults)
{
IEnumerable ….
List ….
// some codes to change the input arguments according to the current step simulation summary results
}
PetrelLogger.InfoOutputWindow("MyMonitor is completed!");
}
//…
}
And then use it:
private void button1_Click(object sender, EventArgs e)
{
// Some codes that define some arguments…
for (int j = 0; j < 8; j++)
{
// some changes in the arguments
Case MyTest;
MyMonitor monit4 = new MyMonitor();
SimulationRoot simroot = SimulationRoot.Get(PetrelProject.PrimaryProject);
using (ITransaction trans = DataManager.NewTransaction())
{
trans.Lock(simroot);
MyTest = simroot.CreateCase(OriginalCase, MycaseNameFunc());
trans.Commit();
}
CaseRunner cRun = SimulationSystem.GetCaseRunner(MyTest);
cRun.Export();
cRun.Run(monit4);
//Wait(); //waits for current process to close
}
}
But the thing is that MyTest case results part are empty after my run is completed. in this case all the results loaded to the petrel when the 8th (last) simulation completes. If I don’t activate the Wait() function, all 8 runs are almost calling simultaneously…
I changed my scenario, my callback after each run is read the simulation results, change something and call next run so
I create my CaseRunnerMonitor class:
public class MyMonitor2 : CaseRunnerMonitor
{
//…
public override void RunCompleted()
{
// define arguments
index++;
if (index <=8)
{
foreach (Slb.Ocean.Petrel.DomainObject.Simulation.SummaryResult sr in simroot.SummaryResults)
{
IEnumerable ….
List ….
// some codes to change the input arguments according to the current step simulation summary results
}
Case MyTest;
MyMonitor monit4 = new MyMonitor();
SimulationRoot simroot = SimulationRoot.Get(PetrelProject.PrimaryProject);
using (ITransaction trans = DataManager.NewTransaction())
{
trans.Lock(simroot);
MyTest = simroot.CreateCase(OriginalCase, MycaseNameFunc());
trans.Commit();
}
CaseRunner cRun = SimulationSystem.GetCaseRunner(MyTest);
cRun.Export();
cRun.Run(monit4);
}
PetrelLogger.InfoOutputWindow("MyMonitor2 is completed!");
}
//…
}
And then use it:
private void button1_Click(object sender, EventArgs e)
{
Index=0;
// Some codes that define some arguments…
// some changes in the arguments
Case MyTest;
MyMonitor monit5 = new MyMonitor();
SimulationRoot simroot = SimulationRoot.Get(PetrelProject.PrimaryProject);
using (ITransaction trans = DataManager.NewTransaction())
{
trans.Lock(simroot);
MyTest = simroot.CreateCase(OriginalCase, MycaseNameFunc());
trans.Commit();
}
CaseRunner cRun = SimulationSystem.GetCaseRunner(MyTest);
cRun.Export();
cRun.Run(monit5);
}
in this situation no need to wait() function is required. But the problem is that I access to MyTest case results in one level before the current run completes. i.e, I can view the step 5 results via MyTest.Results when the run 6 is completed while step 6 results are empty despite of completion of its run.
I check the CaseRunner.IsRunning property and it shows true
This is because Caserunner.Run() is non-blocking; that is, it starts another thread to launch the run. Control flow then passes immediately to your cRunners.IsRunning check which is true as simulation is in progress.
cRunners.Run(); //non-blocking
bool b = cRunners.IsRunning;
You should look at CaseRunnerMonitor if you want a call-back when the simulation is complete.
Edit:
can you show me an example of using CaseRunnerMonitor? both definition of the derived class and its implementation.
Create your monitor class:
public class CustomCaseRunnerMonitor : CaseRunnerMonitor
{
//...
public override void RunCompleted()
{
//This is probably the callback you want
}
}
Use it:
Case myCase = WellKnownSimulators.ECLIPSE100.CreateSimulationCase(...);
CaseRunner runner = SimulationSystem.GetCaseRunner(myCase);
var myMonitor = new CustomCaseRunnerMonitor(...);
runner.Run(myMonitor);
//Your callbacks defined in your CustomCaseRunnerMonitor will now be called
See also "Running and monitoring a Simulation" in SimulationSystem API documentation.
Ah, OK. I didn't realise you were trying to load results with the CaseMonitor.
I'm afraid the short answer is "No, you can't know when Petrel has loaded results".
The long answer is Petrel will automatically load results if the option is set in the Case arguments. (Define Simulation Case -> Advance -> Automatically load results).
In API:
EclipseFormatSimulator.Arguments args = EclipseFormatSimulator.GetEclipseFormatSimulatorArguments(myCase);
EclipseFormatSimulator.Arguments.RuntimeArguments runtimeArgs = args.Runtime;
runtimeArgs.AutoLoadResults = true;
runtimeArgs.AutoLoadResultsInterval = 120; //How frequently in seconds Petrel polls sim dir.
You will have to poll SimulationRoot.SummaryResults (using the same API you are already using) after case has finished.
You should use the CaseRunnerMonitor we discussed to determine when to start doing this, rather than the System.Diagnostics.Process[] parray = System.Diagnostics.Process.GetProcesses(); code you currently have.

How to check if async/await really async?

I have built a certain application( service ) based on async/await new keywords in c# 5.0 using WebApi which it self cool, I have create a call from Oracle db Http_Request, but i have tested and it's not really feels right, how can I unit test the async matter if this?
public async Task<WebResponse> Post(Customer customer)
{
if (!customer.ReturnSuccess()) throw new ArgumentNullException("customer");
_logger.Info(string.Format("Customer validation request - date = {0} \n {1}\t\n", DateTime.Now, customer));
try
{
return await Task.Factory.StartNew(() => _service.EvaluateCustomer(customer));
}
catch (Exception e)
{
_logger.ErrorException("Error", e);
}
return null;
}
Do not Unit Test language features - they are already tested by someone who has much more money than you. Test your business logic instead.
Read msdn about async/await behaviour here:
http://msdn.microsoft.com/en-us/library/vstudio/hh156513.aspx
The method runs synchronously until it reaches its first await
expression, at which point the method is suspended until the awaited
task is complete. In the meantime, control returns to the caller of
the method, as the example later in this topic shows.
I agree with Cheburek in general: don't waste your time unit testing things like await and Task.Run.
However, if you want to ensure your method is properly waiting for EvaluateCustomer, then you inject a service that is under your control and ensure Post only completes after EvaluateCustomer completes:
[TestMethod]
public async Task PostWaitsForEvaluateCustomer()
{
var finishEvaluateCustomer = new ManualResetEvent(false);
var service = new MyFakeService(finishEvaluateCustomer)
{
EvaluateCustomer = _ => finishEvaluateCustomer.WaitOne();
};
var objectUnderTest = new MyObject(service);
Task postTask = objectUnderTest.Post(..);
Assert.IsFalse(postTask.IsCompleted);
finishEvaluateCustomer.Set();
await postTask;
}

How do I simply call an asyc WCF service method using Rx

I have been struggling to figure out how to use Rx. Most of the examples are out of date, reference Begin/End or are long and complex.
I have a simple WCF service method that takes an int and returns a JobMaster object.
Here is how I call it at the moment:
public static void GetJob(int jobId)
{
KernServiceClient.GetJobCompleted += GetJobCompleted;
KernServiceClient.GetJobAsync(jobId);
}
private static void GetJobCompleted(object sender, GetJobCompletedEventArgs e)
{
// JobMaster available in e.Result
}
How do I change this to use Rx?
EDIT
Thanks to Paul's help I have got most of the way there. This is what it looks like now. Only problem is the Subscribe never fires. Any ideas?
public static JobMaster GetJob(int jobId)
{
JobMaster retval = null;
IKernService kernServiceInterface = KernServiceClient;
var getJobFunc = Observable.FromAsyncPattern<int, Server.KernMobileWcfService.JobMaster>(
kernServiceInterface.BeginGetJob, kernServiceInterface.EndGetJob);
var result = getJobFunc(jobId);
result
.Subscribe
(
onNext: x => retval = ConvertJobMaster(x),
onError: ex => ShowError(ex.Message)
);
return retval;
}
http://blog.paulbetts.org/index.php/2010/09/26/calling-web-services-in-silverlight-using-reactivexaml/ // Ignore the ReactiveXaml part
Summary: Cast KernServiceClient to the Interface it implements to get back the Begin/End methods, use FromAsyncPattern.
Seems you're returning "retval" even though you're computing it asynchronously and assigning it from your OnNext handler. Your logic upon receiving the value from the service should be moved into the OnNext handler, or you should return the IObservable to the caller.
what are you doing with retval when you return it?
if you need to do more processing when on next completes do it in the onCompleted event of the subscription

How can I wait for an async WCF service to complete?

The question pretty much sums it up. I have a WCF service, and I want to wait until it finished to do something else, but it has to be until it finishes. My code looks something like this. Thanks!
private void RequestGeoCoordinateFromAddress(string address)
{
GeocodeRequest geocodeRequest = new GeocodeRequest();
GeocodeServiceClient geocodeService = new GeocodeServiceClient("BasicHttpBinding_IGeocodeService");
geocodeService.GeocodeCompleted += new EventHandler<GeocodeCompletedEventArgs>(geocodeService_GeocodeCompleted);
// Make the geocode request
geocodeService.GeocodeAsync(geocodeRequest);
//if (geocodeResponse.Results.Length > 0)
// results = String.Format("Latitude: {0}\nLongitude: {1}",
// geocodeResponse.Results[0].Locations[0].Latitude,
// geocodeResponse.Results[0].Locations[0].Longitude);
//else
// results = "No Results Found";
// wait for the request to finish here, so I can do something else
// DoSomethingElse();
}
private void geocodeService_GeocodeCompleted(object sender, GeocodeCompletedEventArgs e)
{
bool isErrorNull = e.Error == null;
Exception error = e.Error;
try
{
double altitude = e.Result.Results[0].Locations[0].Latitude;
double longitude = e.Result.Results[0].Locations[0].Longitude;
SetMapLocation(new GeoCoordinate(altitude, longitude));
}
catch (Exception ex)
{
// TODO: Remove reason later
MessageBox.Show("Unable to find address. Reason: " + ex.Message);
}
}
There is a pattern, supported by WCF, for a call to have an asynchronous begin call, and a corresponding end call.
In this case, the asynchronous methods would be in the client's interface as so:
[ServiceContract]
interface GeocodeService
{
// Synchronous Operations
[OperationContract(AsyncPattern = false, Action="tempuri://Geocode", ReplyAction="GeocodeReply")]
GeocodeResults Geocode(GeocodeRequestType geocodeRequest);
// Asynchronous operations
[OperationContract(AsyncPattern = true, Action="tempuri://Geocode", ReplyAction="GeocodeReply")]
IAsyncResult BeginGeocode(GeocodeRequestType geocodeRequest, object asyncState);
GeocodeResults EndGeocode(IAsyncResult result);
}
If you generate the client interface using svcutil with the asynchronous calls option, you will get all of this automatically. You can also hand-create the client interface if you aren't using automatically generating the client proxies.
The End call would block until the call is complete.
IAsyncResult asyncResult = geocodeService.BeginGeocode(geocodeRequest, null);
//
// Do something else with your CPU cycles here, if you want to
//
var geocodeResponse = geocodeService.EndGeocode(asyncResult);
I don't know what you've done with your interface declarations to get the GeocodeAsync function, but if you can wrangle it back into this pattern your job would be easier.
You could use a ManualResetEvent:
private ManualResetEvent _wait = new ManualResetEvent(false);
private void RequestGeoCoordinateFromAddress(string address)
{
...
_wait = new ManualResetEvent(false);
geocodeService.GeocodeAsync(geocodeRequest);
// wait for maximum 2 minutes
_wait.WaitOne(TimeSpan.FromMinutes(2));
// at that point the web service returned
}
private void geocodeService_GeocodeCompleted(object sender, GeocodeCompletedEventArgs e)
{
...
_wait.Set();
}
Obviously doing this makes absolutely no sense, so the question here is: why do you need to do this? Why using async call if you are going to block the main thread? Why not use a direct call instead?
Generally when using async web service calls you shouldn't block the main thread but do all the work of handling the results in the async callback. Depending of the type of application (WinForms, WPF) you shouldn't forget that GUI controls can only be updated on the main thread so if you intend to modify the GUI in the callback you should use the appropriate technique (InvokeRequired, ...).
Don't use this code with Silverlight:
private ManualResetEvent _wait = new ManualResetEvent(false);
private void RequestGeoCoordinateFromAddress(string address)
{
...
_wait = new ManualResetEvent(false);
geocodeService.GeocodeAsync(geocodeRequest);
// wait for maximum 2 minutes
_wait.WaitOne(TimeSpan.FromMinutes(2));
// at that point the web service returned
}
private void geocodeService_GeocodeCompleted(object sender, GeocodeCompletedEventArgs e)
{
...
_wait.Set();
}
When we call _wait.WaitOne(TimeSpan.FromMinutes(2)), we are blocking the UI thread, which means the service call never takes place. In the background, the call to geocodeService.GeocodeAsync is actually placed in a message queue, and will only be actioned when the thread is not executing user code. If we block the thread, the service call never takes place.
Synchronous Web Service Calls with Silverlight: Dispelling the async-only myth
The Visual Studio 11 Beta inludes C# 5 with async-await.
See Async CTP - How can I use async/await to call a wcf service?
It makes it possible to write async clients in a 'synchronous style'.
I saw one guy did use ManualReset and waitAll, but he had to wrap all code inside of ThreadPool..
It is very bad idea...thought it works

Asynchronous callback - gwt

I am using gwt and postgres for my project. On the front end i have few widgets whose data i am trying to save on to tables at the back-end when i click on "save project" button(this also takes the name for the created project).
In the asynchronous callback part i am setting more than one table. But it is not sending the data properly. I am getting the following error:
org.postgresql.util.PSQLException: ERROR: insert or update on table "entitytype" violates foreign key constraint "entitytype_pname_fkey"
Detail: Key (pname)=(Project Name) is not present in table "project".
But when i do the select statement on project table i can see that the project name is present.
Here is how the callback part looks like:
oksave.addClickHandler(new ClickHandler(){
#Override
public void onClick(ClickEvent event) {
if(erasync == null)
erasync = GWT.create(EntityRelationService.class);
AsyncCallback<Void> callback = new AsyncCallback<Void>(){
#Override
public void onFailure(Throwable caught) {
}
#Override
public void onSuccess(Void result){ }
};
erasync.setProjects(projectname, callback);
for(int i = 0; i < boundaryPanel.getWidgetCount(); i++){
top = new Integer(boundaryPanel.getWidget(i).getAbsoluteTop()).toString();
left = new Integer(boundaryPanel.getWidget(i).getAbsoluteLeft()).toString();
if(widgetTitle.startsWith("ATTR")){
type = "regular";
erasync.setEntityAttribute(name1, name, type, top, left, projectname, callback);
} else{
erasync.setEntityType(name, top, left, projectname, callback);
}
}
}
Question:
Is it wrong to set more than one in the asynchronous callback where all the other tables are dependent on a particular table?
when i say setProjects in the above code isn't it first completed and then moved on to the next one?
Please any input will be greatly appreciated.
Thank you.
With that foreign key constraint, you must make sure the erasync.setProjects(...) has completed before you insert the rest of the stuff.
I suggest doing the erasync.setEntityAttribute(...) magic in (or from) an onsuccess callback instead of jumping right to it.
You're firing several request in which (guessing from the error message) really should be called in sequence.
Any time you call more than one rpc call; try to think that you should be able to rearrange them in any order (because that's allmost what actually happens because they're asynchronous)... If running them in reverse order does not make sense; you cannot fire them sequentially!
Two ways to fix your problem:
Nesting:
service.callFirst(someData, new AsyncCallback<Void> callback = new AsyncCallback<Void>(){
#Override
public void onFailure(Throwable caught) {/*Handle errors*/}
#Override
public void onSuccess(Void result){
service.callSecond(someOtherData, new AsyncCallback<Void> callback = new AsyncCallback<Void>(){
/* onSuccess and onFailure for second callback here */
});
}
});
Or creating one service call that does both (Recommended):
service.callFirstAndSecond(someData, someOtherData, new AsyncCallback<Void> callback = new AsyncCallback<Void>(){
#Override
public void onFailure(Throwable caught) {/*Handle errors*/}
#Override
public void onSuccess(Void result){
/* Handle success */
}
});
The second option is most likely going to be much less messy, as several nested asynch callbacks quickly grows quite wide and confusing, also you make just one request.
Because of nature of Async, don't assume setProjects(...) method will be called on the server before setEntityAttribute or setEntityType.
Personally, I prefer to have a Project class which contains all necessary info, for example:
public class Project{
private String projectName;
private List attributes = new ArrayList();
.. other properties
// Getter & Setter methods
}
Then send to the server in one round trip:
Project project = new Project();
project.setProjectName(..);
// Set other properties
erasync.saveProjects(project, callback);