Stop main thread until WCF Call returns? - c#

I am new to web services and started out with WCF. I have multiple web service calls, each of which are done asynchronously. But my problem is that the main thread should stop until all the web service calls return and when all the web service calls return only then it should proceed.
I tried two things here :
used a Boolean variable and an infinite loop to stop the main thread. I change the value in the Completed method of the web service call. It resulted in an infinite loop and the Completed never got called.
I made the web service call from the main thread and after making the web service call, I called the Join method on the main thread to stop this thread until the web service returns.
This is the code snippet :
ServerMonitoringBoardDataService.ServerMonitoringBoardDataServiceClient c = new ServerMonitoringBoardDataService.ServerMonitoringBoardDataServiceClient();
c.GetEnvironmentAndServersCompleted += new EventHandler<ServerMonitoringBoardDataService.GetEnvironmentAndServersCompletedEventArgs>(c_GetEnvironmentAndServersCompleted);
c.GetEnvironmentAndServersAsync();
void c_GetEnvironmentAndServersCompleted(object sender, ServerMonitoringBoardDataService.GetEnvironmentAndServersCompletedEventArgs e)
{
var x = e.Result;
}
The reason I am facing problems is that,the multiple web service calls returns data as lists and I have done some operations on this data and then displayed it on the UI.The web service calls are made in a static constructor,so as to fetch the data only once and manipulate and display it many time.
But what happens is that the main thread does not stop until the data is fetched and moves onto perform the operations,where I get a Null Exception.
Please suggest a way out for me and also why the above approaches didn't work.
Thanks in advance for any kind of help on this.

The simplest to code would be to use the async operation model (i.e. you call BeginXXX and it returns an IAsyncResult to you) and follow the procedure outlined here for all of your async calls. This model is supported out of the box if you used the service proxy generator that comes with Visual Studio.
You will start by making the async calls:
var async1 = service.BeginFoo();
var async2 = service.BeginBar();
// more similar calls
And then end them one by one -- order does not matter:
var result1 = service.EndFoo(async1);
var result2 = service.EndBar(async2);
// etc
Of course in practice you will need to add error handling, so it won't be quite as short.

Related

How to covert async call to work as sync call in C#

I'm a newbie in C#, and I'm going to develop a small program using a third party network library to send the requests.
Suppose there have some requests (just simple strings) stored in the queue qTasks, and it will handle those requests one by one with the order as submitted, the queue can be updated during execution, and it should be stopped whenever there has error returned.
I can just use a for loop to call the send request command in the array one by one, but unfortunately the sendrequest command is an async method with callback OnStageChanged, and I need to check the result before sending the next request when the status is "Done".
I'm now using the following method to handle it:
In the main UI Thread,
// Put those request text in a queue names qTasks, then call a goNextTask() to process the request one by one.
// The queue can be updated by the UI thread at anytime, goNextTask will be called periodically to handle those pending request in the queue.
private void goNextTask(bool lastSuccess = true)
{
if (lastSuccess)
{
if (qTasks.Count > 0)
{
// continue to next request
string requestText = qTasks.Dequeue();
SendRequest(requestText, OnStageChangeHandler);
} else {
// Report for all request sent successfully
}
} else {
// stop and show error
}
}
The callback method OnStageChangeHandler will be called by the library whenever the stage changes, and it will have state "Done" when completed.
private void OnStageChangeHandler(object sender, StageChangeEventArgs e)
{
if (e.newState == SessionStates.Done)
{
// check result here
bool success = <...>
// then call the goNextTask in UI thread with the result of current request.
Application.Current.Dispatcher.BeginInvoke(
System.Windows.Threading.DispatcherPriority.Normal,
(Action)(() => goNextTask(success)));
}
}
Although it works fine now, I think it's a little bit stupid as it has a somewhat recursive flow (A -> B -> A -> B ->....).
I learnt that MS has improved the web request handling, so that it can work in sync mode.
I'd like to know if I can have a wrapper to make the above async call work as a sync call, so that it can be done in a simple flow as a loop like that:
while (qTaks.Count > 0)
{
if (!sendAndWaitReturn(qTasks.Dequeue())) {
// Report error and quit
}
}
// all tasks completed
This sendAndWaitReturn method will send the request, then wait for the status "Done", and then return the result.
I found some example that may use a control flag to indicate the status of the current request, and the callback function will update this control flag, while the UI thread will loop on this flag using a while loop:
while (!requestDone);
so that it will not continue to nextRequest until requestDone. But in this case, the UI will be blocked.
Is there any better way to convert the async call to work as a sync call without blocking the UI thread?
The difficulty you're going to run into is you have conflicting desires. On one hand, you want to avoid blocking the UI thread. On the other hand, you don't want to run things asynchronously and so you're going to block the UI thread.
You're going to have to pick one, and there's absolutely no reason to keep on doing things synchronously (especially in light of blocking the UI thread). If it hurts when you do that, don't do that.
You haven't specified, but I'm guessing that you're starting this processing from a button click event. Make the method invoked by that click event async. For example:
private async void StartProcessing_Click(object sender, EventArgs e)
{
await Task.Run(() => StartProcessing());
}
There, you've started processing and the UI thread isn't tied up.
The next thing is that, you're right, having the event behave in that cyclical manner is silly. The event is to notify someone that the state has changed, its goal isn't to manage queue policy. The queue should manage queue policy (or if you'd rather not abstract that out, the method that processes requests).
So how would you do that? Well, you've said that SendRequest hands the session object back to the caller. The caller is presumably the one who is orchestrating queue policy and determining whether or not to call SendRequest again.
Have the caller check the session object for validity and decide whether to keep going based on that.
Additionally, I'm unfamiliar with that particular library, but briefly glancing at the documentation it looks like there's also a SendRequestAndWait() method with the same signature and that sounds like it might better meet your needs.

WCF prevent concurrent background tasks

I am developing a WCF web service that is set up like this:
Web method that is periodically triggered (every 15 minutes) by REST requests from a task scheduler.
When triggered, web method starts a background method using Task.Factory.StartNew. This method involves getting and posting to and from remote APIs and writing to a local database, and sometimes takes several minutes to complete.
As soon as the background method has started, the web method returns a "successfully triggered" message and terminates.
My question is this: will the background method be able to run concurrently on multiple threads if the web method is triggered again while it is still running? I DO NOT want this to happen, as it could cause all sorts of trouble. Ideally I would want multiple calls to queue up and be executed one-by-one on a single background thread.
I'm not sure if Task.Factory.StartNew is the best way to do this either, would be grateful for any suggestions.
You can use TaskFactory.StartNew, if you create a TaskFactory with the right kind of TaskScheduler...
I suggest grabbing the Parallel Extensions Extras nuget package and using the OrderedTaskScheduler to run your tasks:
System.Threading.Tasks.Schedulers.OrderedTaskScheduler sch = new OrderedTaskScheduler();
//you could persist this as static or in the kernel of your favorite DI framework
var taskFactory = new TaskFactory(sch);
for(var i = 0; i < 10; ++i)
{
var x = i;
//these Console operations will occur in order
taskFactory.StartNew(() => Console.WriteLine(x));
//but if we did as below, order would be lost
//Task.Factory.StartNew(() => Console.WriteLine(x));
}
So, you can see, it runs the actions in a single thread in the order that they were added.
If you want to limit the WCF service itself to limit execution to a single thread at a time (I.e. concurrent calls to the service will block and execute one at a time) consider using the following properties of the ServiceBehaviorAttribute you can attach to your service implementation.
InstanceContextMode = InstanceContextMode.Single
https://msdn.microsoft.com/en-us/library/system.servicemodel.servicebehaviorattribute.instancecontextmode(v=vs.110).aspx
ConcurrencyMode = ConcurrencyMode.Single
https://msdn.microsoft.com/en-us/library/system.servicemodel.servicebehaviorattribute.concurrencymode(v=vs.110).aspx

Method takes significant amount of time to return values

Im dealing with a scenario in C#.net where Im loading a page, and during that pageload event, a service is being called to populate a value which is used to diplay on the page.
The page also has other fields. So the issue here is, the service usually takes between 30 to 60 secs to return the value, other fields cannot be selected until this service returns a value. So there is also a "SAVE" button which cannot be clicked since we are still waiting on this service to return the value.
The problem im trying to solve here is, ideally, on pageload, I want this service to run on the background and let other fields populate the value and I should be able to execute other events like SAVE, NEXT PAGE, PREVIOUS PAGE etc when called.
The purpose of the value returned by the service is for reference only. The code does not have any dependency on this value.
If your service has a method call it by making your onpageload callback async and await the asynchronous method inside of it.
If the service does not have an async method to call you can create your own e.g:
public string DownloadStringAsync()
{
return "Test data";
}
public async Task<string> ReceiveStringAsync()
{
return await Task<string>.Run(() =>
{
//Method to download your data
return DownloadStringAsync();
});
}
and await it in your page load: sting data = await ReceiveStringAsync();
You are not providing enough information/code for a better answer.
You can try executing it in a Thread. Something like this
Thread runner = new Thread(() =>
{
// run service call here
});
runner.IsBackground = true;
runner.Start();
But in C# 4.0 there is the new Task Parallelism Library so you can read about that and proceed from there, technically a Task is like a thread, but the difference is that the Task can have continuation aswell as it manages the Thread pool.
Read TPL here: Task Parallelism Library

Execute web service method and return immediately

C# ASP.NET 3.5
Is it possible to "fire and forget" a method in a web service that is not asynchronous or one-way?
There is a method that returns a value (after some processing), which I don't need. It is used by another group (who wrote the service). Basically, it just notifies that user x did action y. I just need to call the method and move on without waiting for the result.
I tried using a BackgroundWorker() with RunWorkerAsync, but the method does not fire for some reason. I cannot change the web service method as I have no access to their code. Should I be using BackgroundWorker, Invoke, ThreadPool, something else? I don't need the result returned, and I don't need to know if it fails. Basically, call the method, and if it works, great. If not, I don't want to stop or slow processing down.
public static void Test()
{
var worker = new BackgroundWorker();
worker.DoWork += Test2;
worker.RunWorkerAsync(new object[] {12345, "test"});
}
private static void Test2(object sender, DoWorkEventArgs e)
{
// Write to log that we got into the method - does not
object[] args = e.Argument as object[];
int num = Convert.ToInt32(args[0]);
string name = (string)args[1];
// call web service method here....
}
Intsead of using Background Worker you can try the following
public static void Test()
{
System.Threading.ThreadPool.QueueUserWorkItem(delegate
{
Test2(new object[] { 12345, "test" });
});
}
private static void Test2(object data)
{
// Write to log that we got into the method - does not
object[] args = data as object[];
int num = Convert.ToInt32(args[0]);
string name = (string)args[1];
// call web service method here....
}
The feature that is requested, by definition IS WCF OneWay. It is impossible to implement the required behavior completely client-side.
IIS by default (a common host of WCF services) is allowed to kill any process that was kicked off by a closed connection. This means that the client must stay connected for the duration of the process (which in effect means waiting for the result). Additionally it is possible the request can timeout and the "fire and forget" process is killed off.
If you only want to reduce the resources taken up at the client to the minimum whilst the request is in flight I would run the request asynchronously. If you only have access to .net<=4.0 then the easiest way to do this is to generate the async calls (I mean APM async and NOT async/await/TPL async) using the "add service reference" option and tick the "generate async methods" option.
You would have to also learn the APM programming model (which is pretty nasty).
Alternatively you could run the WCF call on a separate Thread. But note, this uses significant additional resources.
There is a document here on Asysn/Sync wfc calls. http://msdn.microsoft.com/en-us/library/ms734701.aspx.

ASP.NET MVC2 Can AsyncController access HttpContext.Current?

I'm trying to convert this method ExportTo3rdParty() to use an AsyncController:
public JsonResult SaveSalesInvoice(SalesInvoice invoice)
{
SaveInvoiceToDatabase(invoice); // this is very quick
ExportTo3rdParty(invoice); // this is very slow and should be async
}
But the ExportTo3rdParty() method uses HttpContext.Current in multiple places (far too many to change - the original coder did not use enough dependency injection). For example it calls GetDefaultCurrency(). Will this still work when ExportTo3rdParty() is called through an AsyncController?
public Currency GetDefaultCurrency()
{
Currency currency;
string key = string.Format("DefaultCurrency_{0}",
HttpContext.Current.User.Identity.Name);
currency = HttpRuntime.Cache.Get(key) as Currency;
if (currency == null)
{
currency = LookupDefaultCurrency();
HttpRuntime.Cache[key] = currency;
}
}
I know that if I use Thread.Start that I can not access HttpContext.Current. But what about an AsyncController?
So let me ask you why you want to use an Async controller?
Do you think it's going to be faster? Just because something it slow doesn't mean you need to make it async. In fact you'll most likely find that the method is slower when run async due to thread management/context switching overheads.
From what little I can understand from the two methods you've shown. I'm guessing that ExportTo3Party can basically be done "out of band". That is by an external process. So what you should be doing is either use MSMQ to queue the job (this returns immediately) so it's non-blocking. And have some other process/application process the queued jobs. This other process could be a regular Console application that is kept running on the server (using Task Sheduler) and it simply processes jobs as soon as they arrive in the queue.
Or even simpler (if you've not used MSMQ), simply execute an external application (console app again) and not wait for the app to exit. So you can use System.Diagnostics.Process to start the process and don't WaitForExit.
Both of these alternatives are the right/better way to implement what I think ExportTo3rdParty is doing. Seeing that you're not waiting on a response from this method ot return it.
If I haven't convinced you yet, then:
From MSDN documentation
If an asynchronous action method calls
a service that exposes methods by
using the BeginMethod/EndMethod
pattern, the callback method (that is,
the method that is passed as the
asynchronous callback parameter to the
Begin method) might execute on a
thread that is not under the control
of ASP.NET. In that case,
HttpContext.Current will be null, and
the application might experience race
conditions when it accesses members of
the AsyncManager class such as
Parameters. To make sure that you have
access to the HttpContext.Current
instance and to avoid the race
condition, you can restore
HttpContext.Current by calling Sync()
from the callback method.
If the callback completes
synchronously, the callback will be
executed on a thread that is under the
control of ASP.NET and the operations
will be serialized so there are no
concurrency issues. Calling Sync()
from a thread that is already under
the control of ASP.NET has undefined
behavior.
The ActionCompleted method will always
be called on a thread that is under
the control of ASP.NET. Therefore, do
not call fSync() from that method.
The callback that you pass to the
Begin method might be called using a
thread that is under the control of
ASP.NET. Therefore, you must check for
this condition before you call Sync().
If the operation completed
synchronously (that is, if
CompletedSynchronously is true), the
callback is executing on the original
thread and you do not have to call
Sync(). If the operation completed
asynchronously (that is,
CompletedSynchronously is false), the
callback is executing on a thread pool
or I/O completion port thread and you
must call Sync().
http://msdn.microsoft.com/en-us/library/ee728598.aspx

Categories

Resources