Web Services. Get input data, process it at background thread - c#

I've got several web-services: asmx,wcf. At couple of them there are some methods, which take a lot of time for processing, but size of input data for these methods are small and it takes not much time to transfer on the wire. I want move to not sync model. Client passes data to service, service answers that data transfer was correct and process it at background thread witout connection with client. So agter transfering connection should be closed. IS it possible? Can u help me with articles or may be just google request.

John is right - Once you close an http connection, it is done. You can't get back to the same process.
So if you can use another technology that allows duplex on one connection (e.g. WCF), do it!
However,
if you have no choice but to use webservices,
here are three ways to make it work. You may get timeouts on any of them.
Option 1:
Forget the part about 'client answers data was correct.' Just have each thread make its request and wait for the data.
Option 2:
Now, assuming that won't work and you must do the validation, this way requires the client to make 2 requests.
First request: returns valid/invalid.
Second request: returns the long-running results.
Variation of option 2:
If you have timeout problems, you could have the first request generate a GUID or unique database key and start another process, passing it this key, and return the key to the client. (if you can get the server to allow you to start a process - depends on security settings/needs - if not you may be able to start an async thread and have it keep running after the websvc one ends?) The process will do the long task, update the row in the database w/ the unique id when finished, revealing the results plus a 'done' flag. The second request by the client could always return immediately and if the processing is not done, return that, if it is, return the results. The client will repeat this every 5 sec or so until done.
Hacks, I know, but we don't always have a choice for the technology we use.

Don't do this with ASMX web services. They weren't designed for that. If you must do it with ASMX, then have the ASMX pass the data off to a Windows Service that will do the actual work, in the background.
This is more practical with WCF.

We have been writing stuff to interact with the UK gov website and the way they handle something similar is that you send your request and data to the server and it responds saying, roughly, "thanks very much - we're processing it now, please call back later using this id" - all in an XML message. You then, at some point later, send a new http request to the service saying, essentially, "I'm enquiring about the status of this particular request id" and the server returns a result that says either it has processed OK, or processed with errors, or is still processing, please try again in xx seconds.
Similar to option 2 described previously.
It's a polling solution rather than a callback or 2 way conversation but it seems to work.
The server will need to keep, or have access to, some form of persistent table or log for each request state - it can contain eg, the id, the original request, current stage through the workflow, any error messages so far, the result (if any) etc. And the web service should probably have passed the bulk of the request off to a separate Windows service as already mentioned.

Related

Is it possible to access parameters sent via multipart/form-data without waiting for the entire form to arrive

I have a pretty big video file I upload to a web service via multipart/form-data.
It takes ~ 30 seconds to arrive and I would prefer not waiting that long simply to access parameters I send along with the file.
My question is simple, can I access parameters sent with the form without waiting for the video payload to be uploaded?
Can this be done using headers or any other methods? 
Streaming vs. Buffering
It's about how the webserver is set up. For IIS you can enable Streaming.
Otherwise, by default, IIS will use 'buffering' - the whole request is loaded into memory first (IIS's memory that you can't get to) before your app running in IIS can get it.
Not using IIS? You have to figure out how to get the webserver to do the same thing.
How to stream using IIS:
Streaming large file uploads to ASP.NET MVC
Note the way the file is read in the inner loop:
while ((cbRead = clientRequest.InputStream.Read(rgbBody, 0, rgbBody.Length)) > 0)
{
fileStream.Write(rgbBody, 0, cbRead);
}
Here instead of just saving the data like that question does, you will have to parse any xml/json/etc or whatever contains the file parameters you speak of ... and expect the video to be sent afterwards. You can process them right away if it's a quick process ... then get the rest of the video ... or you can send them to a background thread.
You probably won't be able to parse it just dumping what you have to a json or xml parser, there will be an unclosed tag or } at the top that isn't closed til after the video data is uploaded (however that is done). Or if it's multipart data from a form submission, as you imply, you will have to parse that partial upload yourself, instead of just asking IIS for the post data.
So this will be tricky, you can first start by writing 1k at a time to a log file with a time stamp to prove that you're getting the data as it comes. after that it's just a coding headache.
Getting this to work also means you'll have to have some control over the client and how it sends the data.
That's because you'll at least have to ensure it sends the file parameters FIRST!
Which concerns me, because, if you have control of the client, why can't you take the simple route (as Nobody and Nkosi imply) and use 2 requests? You mention you need one. Why not write js client code to send the parameters first in an XHR and then the file in a second request, using a correlation ID in both to tie them together? (the server could return this from the first request and you could send it in the 2nd).
Obviously, if you're just having a form with some inputs and a file upload and doing submit, then you need one request ;-) But if you have control over the client side you're not stuck with that.
Good luck, there is some advanced programming here, but nothing super high-tech. You will make it work!!!
If you don't have control over the server code, you are probably stuck, if the server app's webserver is buffering, the server app won't get anything, of course, if you wanted to do something with the file parameters first, this really implies you have control of the server side ;-)

ASP.NET WebAPI Ajax with progress

I have a really long webAPI request that basically does the follow :
1. retrieves a list of item categories from the db
2. for each category, retrieve all the items in the category
Now, the entire process takes a very long time and I don't want the user to wait till the entire process is over, if a category has finished loading I want it to return to the client
Does anyone know how I can do that? Send a request and get progress notifications by the server whenever a part of the request has finished?
You could use SignalR to send the data from the server to the client when it's available.
The other option is polling from the client. The client makes the initial request, which triggers a server side process that prepares the data and keeps it somewhere (in memory, in a database). Then the client polls the server for new available data until the server process finishes.
you need to break your request. use for loop. if elements from first category are downloaded then do something with them before going for second category.
so your request will go inside some loop. You can use Jquery or page methods if you are using asp.net webforms
PushStreamContent might help you:
http://weblogs.asp.net/andresv/asynchronous-streaming-in-asp-net-webapi

asp.net: Stop response, Continue execution

In asp.net I want to give the customer an immediate response and close the connection, and then continue execution which may be lengthy and display unimportant messages. But none of this should be visible to the customer.
I already tried Response.Flush / Close / End, CompleteRequest and anonymous delegates, but couldn't get it to work with any of this.
Sample:
Response.Write("time: "+HttpContext.Current.Session["test"]);
MagicallyEndReponse(); //But how?
Thread.Sleep(10000); //Customer should not experience any delay
HttpContext.Current.Session["test"] = DateTime.Now; //This should be available when reloading 15s later
Response.Write("BORING INFO!"); //Customer should not see this
I wouldn't recommend background thread processing in an ASP.NET application, it's not what ASP.NET or IIS is designed for.
My advice would be look at having a separate service (e.g. an internal Windows Service) which picks up work from the website and processes it, this would allow you to write a more robust multi-threaded application. You could use a durable messaging system like MSMQ / NServiceBus to pass messages to / from the service (this would mean no work is lost if the website happened to go down or restart).
The natural response for these types of request would be 202 Accepted and then possibly exposing an API for the client to query to check on the progress.

Best Way to avoid Reinsertion of data in ASP.net on Page Refresh

I want to know what is the best way to avoid the reinsertion of data in ASP.net.
I am currently doing
Response.Redirect('PageURL');
Thanks in Advance
Don't put your insertion code in the Page_Load method, or if you are, make sure you are checking Page.IsPostBack first.
Yes, normally we have an identity autoincrement number id, wich should be sent back to your form after the insertion. So you just have to check on server if that number is > 0 and execute an update instead of an insert.
Your redirect solution is valid. This pattern is called Post/Redirect/Get.
Post/Redirect/Get (PRG) is a web development design pattern that
prevents some duplicate form submissions, creating a more intuitive
interface for user agents (users). PRG implements bookmarks and the
refresh button in a predictable way that does not create duplicate
form submissions.
When a web form is submitted to a server through an HTTP POST request,
a web user that attempts to refresh the server response in certain
user agents can cause the contents of the original HTTP POST request
to be resubmitted, possibly causing undesired results, such as a
duplicate web purchase.
To avoid this problem, many web developers use the PRG pattern[1] —
instead of returning a web page directly, the POST operation returns a
redirection command. The HTTP 1.1 specification introduced the HTTP
303 ("See other") response code to ensure that in this situation, the
web user's browser can safely refresh the server response without
causing the initial HTTP POST request to be resubmitted. However most
common commercial applications in use today (new and old alike) still
continue to issue HTTP 302 ("Found") responses in these situations.
Use of HTTP 301 ("Moved permanently") is usually avoided because
HTTP-1.1-compliant browsers do not convert the method to GET after
receiving HTTP 301, as is more commonly done for HTTP 302.[2] However,
HTTP 301 may be preferred in cases where it is not desirable for POST
parameters to be converted to GET parameters and thus be recorded in
logs.
http://en.wikipedia.org/wiki/Post/Redirect/Get

Asynchronous callback from web api controller

I'm very new to Web API and I have an unusual pattern that I need to implement. In the Post method of my controller, it is to take an object which includes a CallbackURL. It will then immediately return an HTTP response to the caller. Afterwards, it will use a 3rd party, off-site API to perform some work with the object. Once that work is done, the controller is to post the results of that work to the CallbackURL.
However, I do not know how to implement this in Web API. Once I return the HTTP response, the controller's lifecycle is over, correct? If so, how do I perform the work I need to do after I return the response?
If you only need to post results to a url and not to the client that initiated the call, you could possibly do something as easy as this:
public string MyAPIMethod(object input)
{
Task.Factory.StartNew(() =>
{
//call third-party service and post result to callback url here.
});
return "Success!";
}
The api call will return right away, and the Task you created will continue the processing in a different thread.
Creating a task to finish up the request (as suggested by Jason P above) will most likely solve the problem, thread-safety provided. However that approach might hurt the performance of your Web service if calls to the 3rd party API take a significant amount of time to complete and/or you are expecting many concurrent clients. If that was the case, your problem seems to be the perfect candidate for a service pattern called "Request/Acknowledge/Callback" (also "Request/Acknowledge/Relay"). Using that pattern, your Web API method will just store each request (including the callback URL) into a queue/database and return quickly. A separate module (possibly running on more than one machine, depending on the number and complexity of the tasks) will take care of completing the tasks, and subsequently notifying completion through the callback URL (please see http://servicedesignpatterns.com/ClientServiceInteractions/RequestAcknowledge).
This is presuming you want to return the results of your 3rd-party query to the caller.
You're correct, this is outside of what's possible with WebAPI. Once you return the HTTP Response, the client also has no connection to your server.
You should look into Asp.Net SignalR, which allows a persistent connection between the client and server, working in modern browsers, and even back to IE7 (though officially unsupported), as well as supporting non-browser clients.
You can then do a couple of things, all of which require the client to connect to SignalR first.
Option 1: You can call your WebApi controller, which can return, but not before launching a task. This task can query the 3rd party api, then invoke a function on the caller via SignalR with the results that you want to provide.
Option 2: You can call a SignalR Hub action, which can talk back to your client. You can tell your client the immediate response, query the 3rd-party api, then return the results you want to provide.

Categories