After complete of asynchronous call to WCF service I want set success message into session and show user the notification .
I tried use two ways for complete this operation.
1) Event Based Model.
client.GetDataCompleted += new EventHandler<GetDataCompletedEventArgs>(GetDataCompleted);
client.GetDataAsync(id, client);
private void GetDataCompleted(object obj, GetDataCompletedEventArgs e)
{
this.SetNotification(new Notification() { Message = e.Result, Type = NotificationType.Success });
}
In MyOperationCompleted event i can set notification to HttpContext.Current.Session, but I must waiting before this operation will completed and can't navigate to others pages.
2) IAsyncResult Model.
In this way I can navigate to other pages and make asynchronous calls to wcf service, but in GetDataCallback method can't set notification, becouse session = null.
client.BeginGetData(id, GetDataCallback, client);
private void GetDataCallback(IAsyncResult ar)
{
string name = ((ServiceReference1.Service1Client)ar.AsyncState).EndGetData(ar);
this.SetNotification(new Notification() { Message = name, Type = NotificationType.Success });
}
"Generate asynchronous operations" in service reference enabled.
Please help me with this trouble. Thanks.
I'm no wcf expert, but what I've found to work is wrapping your call to the Async version of your method in ThreadPool.QueueUserWorkItem. Without this, I had same blocking issue. So this seems to free up the main thread in your asp mvc to move on while another worker thread waits for the callback.
Also, I used AsyncController, although that alone was not enough without the worker thread.
See this: http://msdn.microsoft.com/en-us/library/ee728598.aspx
I used this as a guide, but still needed the ThreadPool.
Cheers
Related
I followed the Vaadin tutorial (Creating Collaborative Views) for broadcasting events and register on them.
Registration eventRegistration;
#Override
protected void onAttach(AttachEvent attachEvent) {
log.debug("In attach...");
UI ui = attachEvent.getUI();
eventRegistration= Broadcaster.register(
"eventName",
message -> ui.access(() -> {
log.debug("Request to refresh grid...");
presenter.refreshGrid();
ui.push();
}));
}
#Override
protected void onDetach(DetachEvent detachEvent) {
log.debug("In detach...");
if(eventRegistration != null) {
eventRegistration.remove();
eventRegistration = null;
}
}
Everything works except the fact that when refreshing the page, the logic in the onDetach() is not executed. After refresh, however, you will enter the onAttach() method. Because of this you are actually going to register several of 'the same' listeners without removing the previous one and you actually get a doubling of listeners. The onDetach() method is only accessed if you go to another menu item, for example.
You can find an example log below.
What is the Vaadin recommended way to remove these listeners before/during refresh?
The onDetach method should be called eventually.
No event is sent to the server when you close or refresh a tab, and as such the server is not aware that the old UI should be detached.
This is where the heartbeat requests come in. The UIs send heartbeat requests every 5 minutes per default, and if the server notices that the old UI has missed three heartbeats, it will be detached. Alternatively, it will be detached when the session expires.
In other words, the onDetach method should be called after about 20 minutes.
The reason no event is sent to the server when the tab is closed or refreshed is that this could prevent the tab from refreshing/closing while the request is being handled, which is bad user experience. Also, this wouldn't cover the cases where the computer is turned off or the network disconnected.
There is something called the Beacon API that could be used to notify the server when a tab is refreshed or closed without causing a delay in the browser. There is an issue for using this to immediately detach UIs.
I'd recommend using the Unload Beacon add-on: https://vaadin.com/directory/component/unload-beacon-for-vaadin-flow or a similar approach which is demonstrated in the Cookbook: https://cookbook.vaadin.com/notice-closed - essentially, it's executing the JavaScript snippet to add an event listener for Window's unload event:
ui.getElement().executeJs(
"window.addEventListener('unload', function() {navigator.sendBeacon && navigator.sendBeacon($0)})", relativeBeaconPath);
and the beacon is sent to a custom SynchronizedRequestHandler.
Simplest way to workaround the problem would be checking if eventRegistration is null before adding one.
#Override
protected void onAttach(AttachEvent attachEvent) {
log.debug("In attach...");
UI ui = attachEvent.getUI();
if (eventRegistration == null) {
eventRegistration= Broadcaster.register(
"eventName",
message -> ui.access(() -> {
log.debug("Request to refresh grid...");
presenter.refreshGrid();
ui.push();
}));
}
}
Check the other answer by Erik why calling of onDetach is delayed.
I want to run a task like below :
Task.Run(() => GetWeatherAsync());
And this task only sleeps for 20 seconds :
public async void GetWeatherAsync()
{
System.Threading.Thread.Sleep(20000);
}
I want to prevent new user to enter to this scope (Method) until the previous Process is running .
What happens if the current user is waiting in GetWeatherAsync and new user enter .
Using Task.Run doesn't make your method async. Just use the GetWeatherAsync method without another overhead (because it's already async) and ASP.NET runs each request in a new thread. You don't need another thread here.
You should not use async void.
You should not use Thread.Sleep in async methods. It's Task.Delay here.
You can use locking here to achieve your goal:
// only 1 thread can be granted access at a time
static SemaphoreSlim semaphoreSlim = new SemaphoreSlim(1,1);
public async Task GetWeatherAsync()
{
// If no-one has been granted access to the Semaphore, code execution will proceed,
// otherwise this thread waits here until the semaphore is released
await semaphoreSlim.WaitAsync();
try
{
await Task.Delay(20000); // Your code here
}
finally
{
semaphoreSlim.Release();
}
}
P.S.
You need to start reading this Persian course about C# 5, Async.
Suppose I have an Action like below that I want to return the View asap and continue doing some work in the background thread.
public async Task<ActionResult> Index()
{
Debug.WriteLine("Inside Index");
var newCustomer = new Customer
{
Name = "Ibrahim"
};
Task.Run(() => SaveCustomer(newCustomer));
Debug.WriteLine("Exiting Index");
return View();
}
private async Task SaveCustomer(Customer NewCustomer)
{
Debug.WriteLine("Started Saving Customer");
await Task.Delay(2000);
Debug.WriteLine("Completed Saving Customer");
}
I do get the output as intended which is:
Inside Index
Exiting Index
Started Saving Customer
Completed Saving Customer
But what bothers me is that I get a warning that my Index action will run synchronously regardless and I should put an await but then the view is returned after SaveCustomer is completed and the purpose is defeated.
How am I doing this wrong? Any suggestion is appreciated.
But what bothers me is that I get a warning that my Index action will run synchronously
How am I doing this wrong?
Don't force asynchrony from the top down. Instead, start with naturally-asynchronous operations at the lowest level (e.g., EF6 database access), and allow the asynchrony grow from the lowest-level code upward.
Also, on ASP.NET, you should strongly avoid Task.Run.
Applying these two principles results in an Index method like this:
public async Task<ActionResult> Index()
{
Debug.WriteLine("Inside Index");
var newCustomer = new Customer
{
Name = "Ibrahim"
};
await SaveCustomer(newCustomer);
Debug.WriteLine("Exiting Index");
return View();
}
but then the view is returned after SaveCustomer is completed and the purpose is defeated.
Not at all. The purpose of asynchronous ASP.NET code is not to return early to the client. async and await do not change the HTTP protocol. await on the server side yields to the thread pool, not the client.
If you need to return early (and most people don't - they only think they "need" to), then you should use one of the established patterns for returning early (as I describe on my blog). Note that the only proper (i.e., fully reliable) solution entails setting up a reliable queue with an independent background process.
Your Index does not make use of any async feature at all. Why did you mark it async? You must be misunderstanding something, not sure what. Remove the async Task specification.
You get that compiler warning because there is nothing asynchronous in your Index() method. Your Task.Run(() => SaveCustomer(newCustomer)); line means Fire And Forget (non awaited task) - this is very different than asynchronous code. Index() is completely synchronous, while creating a "side Task" to execute sometime in the future. As the other answer mentioned - you could just as well remove the async mark from your method - it's not async.
I have a Struts2 Action class that places a JMS Fetch request for a list of Trade in a JMS Queue. This JMS Fetch message is processed by an external process and can take either a few seconds or even few minutes depending on the number of Trade files to be processed by the external task processing app.
I want to know how to handle this HTTP Request with an appropriate response. Does the client wait till the list of Trades is returned? (client (UI) has to action on it and has nothing else to do meanwhile).
The way I approached it is
HTTP Request -->
Struts2 Action -->
Invokes a Runnable to run in a separate Thread (separate from Action class)
UI waits
Action class thread sleeps till runnable does it's job
When Task completed, return list of Trades to UI
Flow is as follows:
Place JMS Fetch Request on Queue1
ExecutorService for Runnable
CClass cclass = new CClass();
final ExecutorService execSvc = Executors.newFixedThreadPool(1);
execSvc.execute(cclass);
Where CClass implements runnable returning a list of Trades:
List<Trade> tradesList = new ArrayList<Trade>();
#Override
public void run() {
while (true) {
try {
Message message = msgConsumer.receive(); // SYNCHRONOUS / NO MDB
if (message == null){
break;
}
if (message instanceof TextMessage) {
TextMessage txtMessage = (TextMessage) message;
Trade trade = TradeBuilder.buildTradeFromInputXML(txtMessage);
if (trade != null) {
tradesList.add(trade); // tradeList is a CClass class variable
}
}
} catch (JMSException e) {
logger.error("JMSException occurred ", e);
}
}
closeConnection();
}
And while this runnableis executing, I do a Thread.sleep in Action class (to let the Runnable execute in the separate Thread)
// In Action class
try {
Thread.sleep(5000); // some time till when the runnable will get executed
} catch (InterruptedException e) {
e.printStackTrace();
}
execSvc.shutdown();
Problem is If I use Callable with a FutureTask and do a get() , that will be blocking till any result is returned. If I do a Runnable, I have to put Action class Thread to sleep till runnable has executed and tradeList is available.
Using Runnable approach, I am able to get couple of hundred records back to UI giving a 5 second Thread.sleep() in main Action class, but only partially constructed tradeList when thousands of records are to be fetched and shown in UI.
This is clearly Not a fail-proof approach.
Any better approach to suggest ? Please elucidate steps for processing in one complete request - response flow.
Yes there is a much better approach when making a standard HTTP request (with ajax you can do other things).
You want to look at the Struts2 Execute and Wait Interceptor Which has most of the functionality you've already implemented. Also look at the token interceptor... which could be useful (it prevents duplicate requests, but doesn't provide a happy wait screen like exec and wait does).
On GET request I run (something like):
public ActionResult Index(void) {
webClient.DownloadStringComplete += onComplete;
webClient.DownloadStringAsync(...);
return null;
}
I see that onComplete isn't get invoked until after Index() has finished execution.
I can see that onComplete is invoked on a different thread from one Index was executed on.
Question: why is this happening? why is webClient's async thread is apparently blocked until request handling thread is finished?
Is there a way to fix this without starting new thread from ThreadPool (I tried this, and using thread pool does work as expected. Also webClient's callback does happen as expected if DownloadStringAsync is called from a ThreadPool's thread).
ASP.NET MVC 3.0, .NET 4.0, MS Cassini dev web server (VS 2010)
EDIT: Here is a full code:
public class HomeController : Controller {
private static ManualResetEvent done;
public ActionResult Index() {
return Content(DownloadString() ? "success" : "failure");
}
private static bool DownloadString() {
try {
done = new ManualResetEvent(false);
var wc = new WebClient();
wc.DownloadStringCompleted += (sender, args) => {
// this breakpoint is not hit until after Index() returns.
// It is weird though, because response isn't returned to the client (browser) until this callback finishes.
// Note: This thread is different from one Index() was running on.
done.Set();
};
var uri = new Uri(#"http://us.battle.net/wow/en/character/blackrock/hunt/simple");
wc.DownloadStringAsync(uri);
var timedout = !done.WaitOne(3000);
if (timedout) {
wc.CancelAsync();
// if this would be .WaitOne() instead then deadlock occurs.
var timedout2 = !done.WaitOne(3000);
Console.WriteLine(timedout2);
return !timedout2;
}
return true;
}
catch (Exception ex) {
Console.WriteLine(ex.Message);
}
return false;
}
}
I was curious about this so I asked on the Microsoft internal ASP.NET discussion alias, and got this response from Levi Broderick:
ASP.NET internally uses the
SynchronizationContext for
synchronization, and only one thread
at a time is ever allowed to have
control of that lock. In your
particular example, the thread running
HomeController::DownloadString holds
the lock, but it’s waiting for the
ManualResetEvent to be fired. The
ManualResetEvent won’t be fired until
the DownloadStringCompleted method
runs, but that method runs on a
different thread that can’t ever take
the synchronization lock because the
first thread still holds it. You’re
now deadlocked.
I’m surprised that this ever worked in
MVC 2, but if it did it was only by
happy accident. This was never
supported.
This is the point of using asynchronous processing. Your main thread starts the call, then goes on to do other useful things. When the call is complete, it picks a thread from the IO completion thread pool and calls your registered callback method on it (in this case your onComplete method). That way you don't need to have an expensive thread waiting around for a long-running web call to complete.
Anyway, the methods you're using follow the Event-based Asynchronous Pattern. You can read more about it here: http://msdn.microsoft.com/en-us/library/wewwczdw.aspx
(edit) Note: Disregard this answer as it does not help answer the clarified question. Leaving it up for the discussion that happened under it.
In addition to the chosen answer, see this article for further details on why the WebClient captures the SynchronizationContext.
http://msdn.microsoft.com/en-gb/magazine/gg598924.aspx