How to Cancel a RIA Services LoadOperation - c#

I am using RIA services in a Silverlight project. I am using the LoadOperation class on the client side to load some data from the server.
In the process of loading that data the request might be superseded by a newer request for different data. This is based on multiple LoadOperations being made to the server, then the user clicking a cancel button.
If I take my LoadOperation and call the 'Cancel' method on it, the operation seems to cancel, but the server side code is not stopped, and using fiddler I can see that the operation completes and an HTTP status code of 200 is returned.
When you call 'Cancel' what does that do on the server, I would expect it to call a ThreadAbortException or something like that? Can this be improved?

So I had a look at the decompiled RIA Services source and it seems like the cancel is client side only. No change to the server-side process is made.
Basically when you run operation.Cancel(), it makes sure the operation can be canceled (operation.CanCancel), and then marks it as canceled, and triggers the completion action.
This means that the server-side operation still continues, but nothing is done with the response client side when it completes
Once the operation has completed, you'll need to check the operation.IsCanceled property to see if that operation was canceled. If so, just ignore the result.

From what I understand cancel of serverside execution using the loadoperation is not available.
you could tough run your own cancel impelmentation:
(depending on if you are using DomainService base or LinqToEntitiesDomainService base the impelmentation will variate)
sevice side
in your service method start the load in a new thread
put that thread object in the session
your thread object should be in a way that you can cancel the DbConnection...
perpare a service method (Invoke) to Cancel the currently executing
thread object registered in the session, and remove it from the session
client side
call cancel on the LoadOperation object and invoke the cancel request.
one caveat is that you comment out the OnSessionStart and stop in global.asax in order
to execute ria services in a multithreaded way per user else each request will wait till a previous request is finished (this has to do with ria service threads and not our thread object)
hope this helps
best regards
PS: we also use a similar solution for pessimistic lock with RIA Services and EntityFramework, ...

Related

Not able to update UI after background task completion in my ASP.NET application

I am running a long running function as background task in my asp.net application. Before the task completes the main thread exits (I want it that way only, since if I use the await keyword and make main thread wait till background task completes, I get proxy error with message
Proxy Error
The proxy server received an invalid response from an upstream server since the background task is too long
But once after the task completion neither I am able to refresh the page by redirecting to the same page or neither I am able to override the UI. Is there any way to update UI after main thread completes execution.
My code goes like this:
protected void btnImport_Click(object sender, EventArgs e)
{
var task = ImportThread();
if (task.IsCompleted)
{
DisplaySuccess("Import success");
}
else
DisplayError("Import failed");
}
private async Task<bool> ImportThread()
{
try
{
var success = await Task<bool>.Run(() => new Manager().Import().ConfigureAwait(false);
if (task.IsCompleted)
{
DisplaySuccess("Import success");
}
else
{
DisplayError("Import failed");
}
return true;
}
The above async task awaits the method below which is present in another class.
public bool Import()
{
// some operations here
return true;
}
After this method completes the control return backs to ImportThread() but the code written there to override UI is not updating UI. I need to update UI with the status of import. And also from ImportThread control is not going back to button click event method too.
Please help me with any way to update UI the status of import.
Note: I tried using Redirect.Response in ImportThread() to refresh the page, but that didn't work
Your problem is that you have to grasp and under stand the web page lifecycle here.
You have this case in which the web page is sitting on the users desktop:
Now say the user clicks a button.
You now have this:
var task = ImportThread();
if (task.IsCompleted)
Ok, so the web page is up on the server. You can put in even async awaits until the cows come home, but you STILL HAVE THIS:
So as long as your code runs, or waits, the web page is STILL STUCK UP on the server side. ONLY until code completes and exits does the page travel down to the client side.
AGAIN:
Your code behind cannot halt, and cannot wait for something to finish, since if it does, then the page REMAINS up on the server until processing finished.
THEN AND ONLY THEN does the web page make the trip back down to the client side. This then occurs;
And then the SERVER SIDE PAGE IS TOSSED OUT of memory, and all class variables are DESTROYED!!! The web server is now waiting for ANY USER to post back a page for processing!!
So, if you need to run some kind of long running process?
You have a few choices:
post the page, code behind runs, code behind starts a NEW thread, web page makes trip back to client side. At that point, you need a timer + some type of web method call (ajax) to poll or ask the server if the long running process is done. And since a ajax call does NOT have use of any web controls on that page, or page class variables (remember, AFTER the web page travels down back to client side, the web page is NOT NOT EXISTING web server side in memory, nor is ANY of the class variables existing). So, again, this quite much means some kind of timer, or as noted, a timer + code to call some ajax method. and that long running process will have to VERY likely use session() since you don't have use of controls, or even ViewState.
And you don't necessary have to use a ajax call. You could use a simple JavaScript client side routine with a timer that say clicks a button every 1 or 2 seconds, the code behind runs, and it would then have to get the status of that long running process (again probably from session), and then update the display. And then you could also include code to stop the timer when the status has changed to "done" or whatever.
So code behind does not and will not "update" the web page multiple times. You have ONE round trip, and the code behind must run fast, must finish running, and can't even use a AWAIT command, since then the page will STLL wait, and STILL be stuck up on the server.
If you want to go beyond the simple timer trick approach - which I often use?
Then you need to adopt and introduce into your web site something designed for this type of case -
Thankfully, there is signalR for this purpose, and that no doubt the best option and approach for you, since it is designed for exactly your question and scenario.
SignalR
https://learn.microsoft.com/en-us/aspnet/signalr/overview/getting-started/introduction-to-signalr#:~:text=What%20is%20SignalR%3F%20ASP.NET%20SignalR%20is%20a%20library,process%20of%20adding%20real-time%20web%20functionality%20to%20applications.
If you want to asynchronously notify a user (of completion or failure of anything such as a task), you can use web push notification (using firebase messaging cloud) or SignalR sockets. When you use a background task you lose the main thread and unfortunately, there is no way to respond to the related user.

ASP.NET Web Api, Database connection in Threads

I have an issue with using a Database in a thread in my asp.net Application.
When I want to start my application I want to start a thread called "BackgroundWorker" with it, which runs in the background till the whole application is stopped.
The problem is that I have massive problems with the dbContext in the thread.
I I try to start the walker in my Startup.cs in the methods "ConfigureServices" or "Configure" and then initialize the dbContext in the constructor in the Walker like this "dbContext = new ApplicationContext()" it tells me that the connection is not configured, when I try to operate in the while(true) queue on the database.
If I write an own Controller for the Walker which receives a ApplicationContext in his constructor and then starts a Thread like this, if i call this controller once with a GET Request:
public BackgroundWorker(ChronicusContext dbContext)
{
_dbContext = dbContext;
_messageService = new MailMessageService();
}
// GET: api/backgroundworker
[HttpGet]
[Route("start")]
public void StartWorker()
{
//Thread thread = new Thread(this.DoBackGroundWork);
Thread thread = new Thread(() => DoBackGroundWork(this._dbContext));
thread.Start();
}
public void DoBackGroundWork(ChronicusContext _dbContext)
{
while (true)
{
if (_dbContext.PollModels.Any()) //Here is the exception
{
...
}
}
}
Then I receive an System.ObjectDisposedException that the object is already disposed inside the while (true) queue.
I tried those and similar things in many different ways but allways receive exceptions like these two or that the database connection is closed.
Can somebody help me and tell me, how this works?
Thank you!
Generally, server side multithreading for Web Applications does not happen often and is, most times, a huge no no.
Conceptually, your server is "multithreaded", it handles many HTTP requests from clients/users/other servers. For mobile and web architecture/design, your server(s) process multiple requests and your clients are handling asynchronous calls and dealing with waiting for responses from long running calls like your API method StartWorker.
Think of this scenario, you make a request to your WebAPI method StartWorker, the client, making the request is waiting for a response, putting the work on another thread does nothing as the client is still waiting for a response.
For example, let's consider your client an HTML web page with an Ajax call. You call StartWorker via Ajax, you will be loading data into a HTML table. You will desire, from a UX perspective, to put up a progress spinner while that long running StartWorker responds to your HTML Page Ajax call request. When StartWorker responds, the Ajax call loads the HTML table with the StartWorker response. StartWorker has to respond with the data. If StartWorker responds beforehand than you will have to send a push notification, via SignalR, for example, when the other thread completes and has the data you need for the HTML table.
Hopefully, you see, the call to the WebAPI method, takes the same amount of time from a Ajax request/response perspective, so multithreading becomes pointless in this scenario, a most common web application scenario.
You can have your client UI load other UI elements, showing a progress spinner in HTML table UI area, until your database call is complete and responds with the data to your Ajax call. This way your users know things are happening and something is still loading.
If you still need your additional thread in your API for your project needs, I believe you have to be using Entity Framework 6 or greater to support asynchronous queries, see this tutorial:
http://www.codeproject.com/Tips/805923/Asynchronous-programming-in-Web-API-ASP-NET-MVC
UPDATE
Now that I know you need to run a SQL query on a repeating frequency of time, and you have an Azure Web App, what you want to use is Azure Automation if you are using Sql Azure or create a Sql Server Job if you are using a Sql Server instance as your backend
DbContext is not thread safe. You need to create a new context from inside your thread.
public void DoBackGroundWork()
{
ChronicusContext anotherContext= new ChronicusContext();
while (true)
{
if (anotherContext.PollModels.Any())
{
...
}
}
}

How to call a web service in "fire and forget" way from ASP.Net

I have a web service that I want to call from one of my asp.net classes.
I can call my web service successfully.But now I need to call this service asynchronously. I need to call it and NOT wait for the service to complete execution. I don't need to process a response from the service and don't need to verify if the service executed successfully. All I want is to be able to call the service and be free to do other things.
You need to consume web service asynchronously.
Goto and check
AddServiceReference -> Advance -> generate asynchronous operations.
after this async callback events will be available to you for every method
Suppose you have ABC method in you service when you will consume it by as sync these methods will be available to you in your application
1>ABC (fire and wait for output)
2>ABCAsync(fire and forget)
3>ABC callback event(get fired <if ABCAsync is called> when data available in your application)
One way to implement a fire-and-forget approach is to use the IsOneWay property on the OperationContract attribute, like this:
[OperationContract(IsOneWay=true)]
public void SomeMethod(string someValue);
When set to true, the operation won't return a message. Note that methods marked as one-way cannot have return types or ref or out parameters (which makes sense). It also should not be confused with asynchronous calls, because it's not the same thing (in fact, a one-way call can block on the client if it takes a while to get a connection, for example).
See OperationContractAttribute.IsOneWay Property for more information.
Have you tried this:?
http://msdn.microsoft.com/en-us/library/bb885132(v=vs.110).aspx
this is another way to do it, check it out.

Cancel async web service calls

I need to be able to cancel async calls made to my webservice. One solution I have is to use manage my own threads, and use synchronous methods from the SOAP client. This works fine and it needs some more fine grained thread management.
If I used any of these two patterns provided from adding a web service reference, say:
var Client = new ASL_WS.SvcSoapClient()
IAsyncResult result = Client.BeginAuthenticateUser(Email, Password, new AsyncCallback(AuthCompleted));
or
var Client = new ASL_WS.SvcSoapClient()
Client.AuthenticateUserCompleted += AuthCompleted;
Client.AuthenticateUserAsync(Email, Passsword);
do any of these two patterns give me a way of cancelling the request? One use case could be: a user logs in, but wants to cancel before the authenticate call completes.
Of course, I could implement this differently by modifying the asyncState passed to these calls, and setting it to disable UI update, but it's not what I'm looking for.
Could I just just cancel all outstanding operations. Does Client.Abort() cancel such operations. What if there are many async requests, are all cancelled? Are there any other API methods that can do this?
Yes, you can use Abort method but keep below notes in mind. You can also use CancelAsync.
Abort notes: http://msdn.microsoft.com/en-us/library/aa480512.aspx
When you call the Abort method, any outstanding requests will still complete, but they will complete with a fault. This means that if you are using callbacks, your callback function will still be called for each outstanding request . When the EndInvoke method is called, or in our case, the wrapper function EndDelayedResponse, then a fault will be generated indicating that the underlying connection has been closed.
CancelAsync example: http://www.codeproject.com/KB/cpp/wsasync.aspx

Block thread until WCF callback is raised?

Is it possible to wait on a callback in WCF? Given this article, I will raise a callback in my WCF service, but I want the client (a seperate application) to only proceed (ie go to the next line of code, e.g. close a form etc, after the callback is raised. So I need to block until the callback is raised.
How could I do this?
Instead of using callbacks, you could call the service synchronously from the client.
If the client does not require any data to be returned, you could return a void, and the client will still wait for the call to complete.

Categories