I was given the task of creating a web based client for a web service.
I began building it out in c# | .net 4.0 | MVC3 (i can use 4.5 if necessary)
Sounded like a piece of cake until I found out that some of their responses would be asynchronous. This is the flow ... you call a method and they return a response of ack or nack letting you know if your request was valid. Upon an ack response you should expect an async response with the data you requested, which will be sent to a callback url that you provide in your request.
Here are my questions:
If I'm building a web app and debugging on localhost:{portnum} how can I give them a callback url.
If I have already received a response (ack/nack) and my function finishes firing isn't my connection to the client then over ? How would I then get the data back to the client? My only thought is maybe using something like signalR, but that seems crazy for a customer buy flow.
Do I have to treat their response like a webhook? Build something separate that just listens and has no knowledge of the initial request. Just save the data to a db and then have the initial request while loop until there is a record for the unique id sent from the webhook.... oye vey
This really has my brain hurting :-/
Any help would be greatly appreciated. Articles, best practices, anything.
Thanks in advance.
If you create your service reference, it will generate a *ServiceMethod*Completed delegate. Register an event handler on it to process your data.
Use the ServiceMethod_Async() method to call the service.
The way I perceived your question is as follows, though please correct me if I'm wrong about this:
1) You send a request to their endpoint with parameters filled with your data. In addition, you send a:
callback url that you provide in your request. (quoted from your question)
2) They (hopefully) send an ack for your valid request
3) They eventually send the completed data to your callback url (which you specified).
If this is the flow, it's not all that uncommon especially if the operations on their side may take long periods of time. So let's say that you have some method, we'll call it HandleResponse(data). If you had originally intended to do this synchronously, which rarely happens in the web world, you would presumably have called HandleResponse( http-webservice-call-tothem );
Instead, since it is they who are initiating the call to HandleResponse, you need to set a route in your web app like /myapp/givemebackmydata/{data} and hook that to HandleResponse. Then, you specify the callbackurl to them as /myapp/givemebackmydata/{data}. Keep in mind without more information I can't say if they will send it as the body of a POST request to your handler or if they will string replace a portion of the url with the actual data, in which case you'd need to substitute {data} in your callback url with whatever placeholder they stipulate in their docs. Do they have docs? If they don't, none of this will help all that much.
Lastly, to get the data back on the client you will likely want some sort of polling loop in your web client, preferably via AJAX. This would run on a setInterval and periodically hit some page on your server that keeps state for whether or not their webservice has called your callback url yet. This is the gnarlier part because you will need to provide state for each request, since multiple people will presumably be waiting for a callback and each callback url hit will map to one of the waiting clients. A GUID may be good for this.
Interesting question, by the way.
Related
We are trying to Consume REST API, for message processor which has some operation which might take more than configured timeout.
Would like to know, if the timeout of Http call to API, will stop execution of API, or API will keep executing?
Idea is that, we can fire and forget API, we are not worried if API does not return 404 or 503. But would like to hear if API will continue to execute?
Any input or suggestion appreciated.
You should use some kind of background processing to handle the process.
I recommend using Hangfire for it.
https://www.hangfire.io/
Use Hangfire to enqueue a job, it will return a job id. You can return this job id to client side.
Expose another API to check for the status of this job.
Great way is to handle this with callback/observer pattern. First of all, understand that there are two types of timeout, server and client. You can explicitly specify client timeout, server timeout is handled by server itself.
So, you will need to implement algorithm such that,
you identify each request unique way and mark it before firing into
memory or file/db.
Fire request with associated callback method.
Hence on response you have control to do stuff like, mark request
fulfilled or failed or what ever it is.
Mark/delete request data.
I'm trying to extend WebAPI to support returning a response through an HTTP callback.
Workflow:
WebAPI receives a HTTP request with a callback URL.
WebAPI handles the URL normally and if the operation completes in less time than a configured timeout the result is sent synchronously.
If the timeout is exceeded the server needs to send an HTTP response indicating it went async, processing continues.
When processing (eventually) completes the response of the controller is posted to the pre-negotiated callback url.
Controllers need to remain synchronous and unaware of the async/callback functionality.
It appears MessageHandlers are a likely candidate but returning multiple HTTP responses (one for the early 'long task' response and one for the callback) does not appear to be supported.
Can someone provide guidance on what areas of WebAPI are extensible and relevant to this scenario?
I think an HttpMessageHandler will do the trick but not the way I think you're asking for.
One URL will be the main one and will return either the result or the redirection and the other will handle the redirections.
This is a very common scenario. In some cases you'll ask for a list of something and receive the a managed amount of results and a continuation URL if there are more. You requirement might be looked up as being just that where you either only have a continuation or the whole results.
Another way of looking at it as CQRS (Command Query Responsibility Segregation). You issue a command to on URL and retrieve the response from another. As an optimization, the result of invoking the command might be the response instead of the query URL.
Does this help you?
I have a long running operation you might read in couple of my another questions (for your reference here is first and second).
In the beginning of whole deal, project expose a form in which user should specify all necessary information about XML file and upload XML file itself. In that method all user input data caught and went to an WCF service that handles such king of files. Controller got only task id of such processing.
Then user got redirected to progress bar page and periodically retrieves status of task completeness, refreshes the progress bar.
So here is my issue comes. When processing of XML file if over, how can I get results back and show them to user?
I know that HTTP is stateless protocol but there is cookie mechanism that could help in this situation. Of course, I may just save processing results to some temporary place, like a static class in WCF server, but there is a high load on service, so it will eat all of supplied memory.
In other words, I would like to pass task to WCF service (using netNamedPipeBinding) and receive results back as fast as it really possible. I want to escape temporary saving result to some buffer and wait until client will gather it back.
As far as I go is using temporary buffer not on service side but at client's:
using (XmlProcessingServiceClient client = new XmlProcessingServiceClient())
{
client.AnalyzeXmlAsync(new Task { fileName = filePath, id = tid });
client.AnalyzeXmlCompleted += (sender, e) =>
{
System.Web.HttpContext.Current.Application.Lock();
// here is I just use single place for all clients. I know it is not right, it is just for illustrating purposes.
System.Web.HttpContext.Current.Application["Result"] = e;
System.Web.HttpContext.Current.Application.UnLock();
};
}
I suggest you to use a SignalR hub to address your problem. You have a way to call a method on the client directly to notify the operation completed. And this happen without having to deal with the actual infrastructure trouble there is in implementing such strategies. Plus SignalR plugs easily in an asp.net MVC application.
To be honest I didn't really get the part about the wcf server and stuff, but I think I can give you more of an abstract answer. To be sure:
You have a form with some fields + file upload
The user fills in the form and supplies an XML file
You send the XML file to an WFC services which procress it
Show in the mean time a progress bar which updates
After completion show the results
If this is not want you want or this is not what your question is about you can skip my answer, otherwise read on.
Before we begin: Step 3 is a bit ambiguous: It could mean that we send the data to the service and wait for it to return the result or that we send the data to the service and we donĀ“t wait for it to return the result.
Situation 1:
Create in a view the form with all the required fields
Create an action in your controller which handles the postback.
The action will send the data to the service and when the service returns the result, your action will render a view with the result.
On the submit button you add an javascript on click event. This will trigger an ajax call to some server side code which will return the progress.
The javascript shows some sort of status bar with the correct progress and repeats itself every x seconds
When the controller finishes it will show the result
Situation 2:
-
-
After sending the data to the service the controller shows a view with the progress bar.
We add an javascript event on document ready which checks the status of the xml file and updates a progressbar. (same as the onclick event in step 4 in situation 1)
When the progressbar reaches 100% it will redirect to a different page which shows the results
Does this answer your question?
Best regards,
BHD
netNamedPipeBinding will not work for cross-machine communication if this is what you have in mind.
If you want to host our service on IIS then you will need one of the bindings that use HTTP as their transport protocol. Have a look at the duplex services that allow both endpoints to send messages. This way the server can send messages to the client anytime it wishes to. You could created a callback interface for progress reporting. If the task is going to take a considerable amount of time to complete, then the overhead of the progress reporting through HTTP might be ok.
Also have a look at Building and Accessing Duplex Services if you want to use a duplex communication over HTTP with Silverlight (PollingDuplexHttpBinding).
Finally you could look for a Comet implementation for ASP.NET. In CodeProject you will at least a couple (CometAsync and PokeIn).
I'm not sure if this is the best solution but I was able to do something similar. This was the general setup:
Controller A initialized a new class with the parameters for the action to be performed and passed the user's session object
The new class called a method in a background thread which updated the user's session as it progressed
Controller B had json methods that when called by client side javascript, checked the user's session data and returned the latest progress.
This thread states that using the session object in such a way is bad but I'm sure you can do something similar with a thread safe storage method like sql or a temp file.
I have a class library I developed that is rather processing intensive that I currently call through a WCF REST service.
The REST service directly accesses the DLLs for the class library and more or less the WCF rest service is an interface for the system.
Let's say the following methods are defined:
Create Request
Starts a thread that takes five minutes, but immediately returns a session ID that the process generates and the thread uses to report when it is completed to the database.
Check Status
Accepts a session id and checks the database to see if the process has completed.
I have to think that there is a better way to "manage" the threads running, however, my requirements state that the user should receive an immediate response from the REST service upon issuing a request.
I am using the WCF Message property to return XML to the browser and as this application can be called from any programming language I can't use classic WCF and callbacks (I think, correct me if I am wrong).
Sometimes I run into an issue where an error occurs and the iscomplete event never gets written to the database and therefore the "Check Status" method says it's processing forever.
Does anyone have any ideas about what is normally done and what can be done in this situation?
Thanks!
Jeffrey Kevin Pry
Your service should return a 202 Accepted at the initial request with a way for the client to check the current status, either through the Location header or as part of the content.
As you indicate the client then polls the URL indicated to check the current status. I would also suggest adding a bit of cache time to this response in case a client just starts looping.
How you handle things on the server is up to you and in no way related to REST. For one thing I would put all logic that executes as the background thread in a try/catch to you can return an error status back if an error occurs and possibly retry the action depending on the circumstances.
I implemented a similiar process for importing/processing of large files and to be honest, I have never had a problem. Perhaps resolving the reason that the IsComplete never gets set will make this more resilient.
Not much of an answer, but still..
I am using ASP.Net + .Net 3.5 + VSTS 2008 + IIS 7.0 + C# to develop a web application. I find when debugging in VSTS 2008, if I call Response.Close() method in page_load (please refer to code below), there will be error (from IE when accessing the page) like can not connect to server.
My question is,
Normally when should we call Response.Close()? Or no need to call (rely on ASP.Net framework to automatically close)?
BTW: my previous understanding is developer should always call Response.Close when processing is completed at server side and all data has been written to client using Response.Write. Am I correct?
2 Why I met with such error in my code? What is the root cause?
protected void Page_Load(object sender, EventArgs e)
{
Response.Write("Hello World! ");
Response.Close();
}
The following from the MSDN website might be useful here:
This method terminates the connection to the client in an abrupt manner and is not intended for normal HTTP request processing. The method sends a reset packet to the client, which can cause response data that is buffered on the server, the client, or somewhere in between to be dropped.
You might use this method in response to an attack by a malicious HTTP client. However, typically you should call CompleteRequest instead if you want to jump ahead to the EndRequest event and send a response to the client.
You should not normally use the Response.Close method in "normal" ASP.NET processing.
All of your data that is written to a HttpResponse "stream" is buffered before being sent to the client browser. The Response.Close method will abruptly terminate the HTTP connection and you may lose data that you have previously Response.Written inadvertently.
If you really want to programmatically "force" the end of a response stream, you should use either: Response.Flush(); followed by Response.End();
The Response.Flush method call ensures that all data that you may have written to the response stream is "flushed" to the client, and Response.End ensures all currently buffered data is correctly sent to client, and also raises the EndRequest event, which you may want to handle.
You can also use the HttpApplication's CompleteRequest() method.
The MSDN documentation states it best:
This method terminates the connection
to the client in an abrupt manner and
is not intended for normal HTTP
request processing. The method sends a
reset packet to the client, which can
cause response data that is buffered
on the server, the client, or
somewhere in between to be dropped.
You might use this method in response
to an attack by a malicious HTTP
client. However, typically you should
call CompleteRequest() instead if
you want to jump ahead to the
EndRequest event and send a response
to the client.
In my experience there is no reason to call Response.Close(); within the code example you've provided, just remove it.
In the pages lifecycle after the Page_Load is fired, there are a number of other methods that will be called that will close your responses for you.
Read here for the Page Lifecycle
To answer question 1:
You should call Response.Close() when your need to terminate the connection - that is, nothing else needs to be sent to the client at all. This does not include what you have posted, since the rest of the page needs to be processed and sent to the client. Normally you would call it when returning data that is not a page from an aspx page (for example a pdf file, an image etc...).
To answer question 2:
You should not call Response.Close() in your Page_Load event handler - it will mean that the rest of the page lifecycle will not run properly.
From MSDN (HttpResponse.Close method):
This method terminates the connection to the client in an abrupt manner and is not intended for normal HTTP request processing. The method sends a reset packet to the client, which can cause response data that is buffered on the server, the client, or somewhere in between to be dropped.
.NET is a very flexible network it will let you do anything you could before .NET. (and more obviously). But the most wonderfull thing is that .NET will take care of verything it can take care of for you.
That means if you create and empty web page and run it in your browser you don't have to do anything else to make it work.
Sometimes however you might find yourself in a situation where you need to do something extraordinary and you will be thankfull for the existance of functions like Reponse.Close()
In your case you're not doing such a thing so there's no need for any special function calling.
Besides that Response.Write() is what we used to use back in the days...Are you still thinking in the classic ASP mode maybe?
Suggestion: Don't use Response.Write()
But put a label in your web page and use:
this.Label1.Text = "Hello world";
Addtional comment:
The purpose of ASP.Net in particular is to send web pages to a browser, collect any posted data, process it, interact with the server OS and so on.
So you might, in my opinion, assume that some care has been taken in 1) serving pages fast and 2) making sure nothing goes wrong when the user follows the guide lines on how to program .Net web pages.
There's no need to implement ALL Page event handlers. Understand the framework, understand what each page event does and learn when to implement which event.
If you're only going to show data from a database you don't even need event handlers.
Read about the Data Controls (Data sources, GridView, ListView, Repeater, etc).
Assume that if you do nothing, the framework will do it for you.
(IF you do nothing at all, nothing happens, that's by design)
Cheers.