MVC 4: How to display visual feedback while an Action executes? - asp.net-mvc

I have an Action (Controller Action)that can take a couple minutes to run under some circumstances. I would like to provide our users a visual indication that the Action is running, such as a message, a spinner, or a progress bar. The trouble is, I'm having a tough time figuring out how to "detect" on the front end that the Action has completed.
After researching this for a bit, I stumbled across an article titled "Using Asynchronous Methods in ASP.NET MVC 4." It explains the use of asynchronous actions and .NET Tasks. It looks like good stuff, and I'm going to spend some time studying it, but I am too new to the concept to really understand if it is going to give me what I want.
So, my question to the SO community is, if you have lots of experience with Asynch Actions and Tasks, are these going to help me provide visual feedback to my users while my Action executes? Or, am I starting down the wrong trail?
EDIT:
Thanks, everyone, for your responses. Sorry for my delayed return to this. After having posted this, I realized I got this situation a bit wrong. It turns out what I really need is a FileResult that generates a PDF and then returns it to the browser, and for a visual indicator to be shown to the user while the file is generated.
In my opinion, this is an entirely different question. So, I'll post it as a separate question.

Using an Asynchronous Controller would free up IIS request threads but it won't help you solve your problem. You probably don't need to do much research in this area if you're not already concerned about many long-running user requests coming in at once (enough to starve the IIS request pool).
If you have a traditional Post, Redirect, Get flow, you can easily show a spinner on post which will go away when the browser gets its response and redirects to the new page.
If you are using asynchronous JavaScript, you can show the spinner in your call and hide it in your completion handler.
I would suggest you don't try to start your own background tasks or threads from IIS because it can recycle your app domain at any time. With a user request it will normally drain stop but it won't know about any additional background tasks you start. You can register your object with IIS so it will first notify you before it intends to tear your app domain down but you can only hold off for up to 30 seconds before IIS will continue anyway. Since your work typically takes longer than this to complete, I'm suggesting this more complicated route is probably not going to work well for you and will make your code a bit more complex.
It really comes down to your requirements. Is it alright to make the user wait for the work to complete before they can continue using your application or do they need to be able to continue to interact while waiting for the work to complete?
If you can make them wait, go with the Post, Redirect, Get pattern and a modal spinner you pop up on submit.
If the user must be able to keep working, you're going to need a PartialResponse action and AJAX calls with handlers to show and hide a non-modal spinner to indicate work is in progress.

You could simply have a page, then kick off an AJAX request to your action. When you kick off the request, show a spinner.
You would then hide the spinner when the AJAX request succeeds or errors out.
With this approach, you would not need to have the Action method be asynchronous since you are not tying up the UI.

This is an example of an approach I take with longer running processes to avoid blocking the UI thread and giving visual feedback to the user.
I will demonstrate with a generating report example, this requires .net 4.5.
Create a method around the report generating processing that returns a task.
As an example please see below:
private Task RunReport()
{
return Task.Run(() =>
// The below should contain your generate report code
Thread.Sleep(5000)
);
}
Then make your Action return a task and put an await before calling the report.
This will unblock the UI thread allowing users to continue using the site while the report is being generated. The content is what will be returned to page when it has finished processing.
[HttpPost]
public async Task<ActionResult> RequestReportGen()
{
await RunReport();
// Add your link to the report in the content below
return Content("Report generated!";
}
Include the following javascript libraries:
<script src="#Url.Content("~/Scripts/jquery-1.8.2.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.unobtrusive-ajax.min.js")" type="text/javascript"></script>
Then use an ajax form to post to your method, please note the LoadingElementId (displays when waiting) and the UpdatedTargetId (displays the finished message).
#using (Ajax.BeginForm("RequestReportGen", "Home", new AjaxOptions { UpdateTargetId = "result", LoadingElementId="loading" }))
{
<div id="loading" style="display:none;">Generating Report...</div>
<div id="result"></div>
<input type="submit" />
}
Using the above method your user can still use the site as your UI thread is not blocked and messages are relayed back to the user when loading and on completion.

Related

Refresh a Sitecore rendering after logon

I feel like this should be obvious, but I'm stumped. We're running Sitecore 7.1 with MVC.
There is a Header rendering that includes conditional logic depending on the status of Sitecore.Context.IsLoggedIn. Works fine.
There is a second rendering that either allows the user to log in OR displays account information. When the [HttpGet] acton is called, the controller checks IsLoggedIn and returns one of two views. When the [HttpPost] action is called (i.e. when the user logs in), The controller calls AuthenticationManager.Login() and then returns the view with the account info. Works fine.
It's a simple solution that allows us to place one rendering on the page, and it works great, except for one thing: the header rendering still shows the not-logged-in content immediately after logging in.
Caching is turned off on the header rendering and in the presentation details. When any link is clicked or the page reloads, the header updates to show the correct info. The problem is only after the initial request/response, when the login form submits and returns an alternate view. Although we've had a complete HTTP request/response cycle, it's like Sitecore doesn't bother to check anything except the rendering that was directly affected.
I know I can solve this by returning a hard Redirect() after logging in but that seems inelegant and creates annoyances, like losing ViewBag info.
What I am really looking for is a way to tell Sitecore, "hey, refresh that other rendering!"
The fact that I can find nothing at all on-line about this 'problem' tells me I might be doing something conceptually wrong.
As I see it there are two ways of handling this problem:
FormHandler
You use #Html.FormHandler to specify a Controller and an Action to handle the authentication. The FormHandler action will execute very early (see: https://twitter.com/dmo_sc/status/480001473745399809) in the page execution, before anything is rendered, and all your Renderings will have the same view of whether users are logged in or not.
Martina did a good writeup on Sitecore MVC and forms:
https://mhwelander.net/2014/05/28/posting-forms-in-sitecore-mvc-part-1-view-renderings/
https://mhwelander.net/2014/05/30/posting-forms-in-sitecore-mvc-part-2-controller-renderings/
Post-Redirect-Get
I really want Sitecore MVC to have this feature build in, as it is useful for all form submission scenarios (bar AJAX). The idea is to handle the POST request and work out what you want to respond (and store this in tempdata). Instead of returning a ViewResult you issue a redirect to the same URL, this forces a GET to the page (at this point all the logged in state is same for all Renderings) where you fish the result out of tempdata. Also P-R-G protects against resubmitting POST requests.
cprakash documented his experience doing P-R-G:
https://cprakash.com/2015/01/12/sitecore-mvc-form-post-simplified/
Off Topic: Multiple forms on single page
This will not solve the OP problem, but worth having a look at in this context:
http://reinoudvandalen.nl/blog/ultimate-fix-for-multiple-forms-on-one-page-with-sitecore-mvc/
In MVC, your renderings are executed sequentially, top to bottom. So if your header rendering comes before the login status rendering, it's going to be done before the user is logged in.
The elegant way to do this would probably be to do your post and update both elements via JavaScript. If you want to keep the header logic separate from the login status logic, your login status script could allow other components to register their own callbacks. You could even build out a client-side message bus, if you will be doing this sort of thing frequently.
You could take a look at Jeremy's approach:
https://jermdavis.wordpress.com/2016/04/04/getting-mvc-components-to-communicate/
The key takeaway, I think, is where he switches the order of the placeholders by placing the results into variables and then render them wherever you want them.
#{
HtmlString main = Html.Sitecore().Placeholder("MAIN");
HtmlString head = Html.Sitecore().Placeholder("HEAD");
}
<head>
#head
</head>
<body>
#main
</body>

How to write on MVC web-page result of continuous operations

I have continuous operation on web-server (read-write cycle from sourceFTP to targetFTP with many transformation data). Technology of my site is ASP MVC 3. How I may write to my web-page result of which successful portion of my operation - such as Response.Write, but my page is very complex (master page and many controls). For example
Function Start() As ActionResult
while true
...
Response.Write (".") 'How to do this???
...
End While
End Function
You generally don't use Response.Write() in an MVC application. And you definitely don't use an infinite loop, since it would cause the page to never finish processing and never be sent to the browser.
If I understand correctly, you want to display a page to the user and have that page constantly update with information from the server. If that's the case then you don't want the long-running process to be on the page, you want it separated from the page. The page just presents the UI, which is going to contain some JavaScript code to update the UI based on data received from the server.
In order to push updates from the server to the browser, take a look at SignalR. There are a couple of different ways to do it, depending on what the browser supports, and this library abstracts them nicely.
Specifically, this walk-through sounds like it's very close to the functionality you're looking for. There's a server-side loop to process information and a client-side loop to update the UI in response to that information. And SignalR simply provides the communication channel between the two.
Essentially what you're asking is not a trivial operation and is somewhat broad. But the basics of it are that you can't just expect the browser and the server to communicate in real-time on their own. You need to write the code which does that.

Callback in Rails after view render (for logging purposes)

Short version: Is there a callback when the rails view is finished rendering?
Longer explanation of my actual problem:
I have this issue where I want to generate a history-object because of some APIs I'm using. So I will be appending to this history object possibly several times before saving it. I know that I can safely save it when the view is rendered, because then there will not be any more calls to the APIs.
After quite a while of googling I can still not find any way of doing this. Is my intended approach the right one, to get a callback from the renderer that says "now everything is rendered. Go ahead and save", or should I do it in a different way?
Does such a callback even exist, or do I need to make it myself?
I would lean towards suggesting that you shouldn't be leaving functionality until after the page has rendered - you should really have completed any API calls in the controller before you start outputting the page. However, if you really must do this you can use javascript to fire off a function (such as an ajax request to an action) after a page has finished rendering.
http://api.jquery.com/ready/ should give you a good starting point!

Showing status of current request by AJAX

I'm trying to develop an application which modifies a couple of tasks of the famous Online-TODO List RememberTheMilk (rememberthemilk.com) using the REST API.
Unfortunately the modifying takes a lot of time, so I want to give a feedback to the users.
My idea was just to display a couple of text lines (e.g. modifying task 1 of n...).
Therefore I used the periodically_call_remote on my page and called a which reads a Singleton.
In the request I store the text that should be displayed in the same singleton. But I found out, that once I set up a request, the periodically_call_remote does not update the specified div.
My question to this:
1. is this a good way to implement this behaviour?
2. if it is, how do get the periodically_call_remote to work during a submit?
Using a Singleton is most definitely a bad idea. In an advanced production setup it isn't guaranteed that subsequent requests will go to the same process or to the same machine (and subsequently will have a different Singleton). Plus, if you have many users, I don't even want to think about what'll happen to those poor Singletons.
Does any of this stuff actually need to go through your Rails app? It seems like you can call the RTM API via Javascript from the page the user is on and then update the page when the XHR request is complete.

What is a postback?

I'm making my way into web development and have seen the word postback thrown around. Coming from a non-web based background, what does a new web developer have to know about postbacks? (i.e. what are they and when do they arise?)
Any more information you'd like to share to help a newbie in the web world be aware of postbacks would be most greatly appreciated.
The following is aimed at beginners to ASP.Net...
When does it happen?
A postback originates from the client browser. Usually one of the controls on the page will be manipulated by the user (a button clicked or dropdown changed, etc), and this control will initiate a postback. The state of this control, plus all other controls on the page,(known as the View State) is Posted Back to the web server.
What happens?
Most commonly the postback causes the web server to create an instance of the code behind class of the page that initiated the postback. This page object is then executed within the normal page lifecycle with a slight difference (see below). If you do not redirect the user specifically to another page somewhere during the page lifecycle, the final result of the postback will be the same page displayed to the user again, and then another postback could happen, and so on.
Why does it happen?
The web application is running on the web server. In order to process the user’s response, cause the application state to change, or move to a different page, you need to get some code to execute on the web server. The only way to achieve this is to collect up all the information that the user is currently working on and send it all back to the server.
Some things for a beginner to note are...
The state of the controls on the posting back page are available within the context. This will allow you to manipulate the page controls or redirect to another page based on the information there.
Controls on a web form have events, and therefore event handlers, just like any other controls. The initialisation part of the page lifecycle will execute before the event handler of the control that caused the post back. Therefore the code in the page’s Init and Load event handler will execute before the code in the event handler for the button that the user clicked.
The value of the “Page.IsPostBack” property will be set to “true” when the page is executing after a postback, and “false” otherwise.
Technologies like Ajax and MVC have changed the way postbacks work.
From wikipedia:
A Postback is an action taken by an
interactive webpage, when the entire
page and its contents are sent to the
server for processing some information
and then, the server posts the same
page back to the browser.
Expanding on the definitions given, the most important thing you need to know as a web-developer is that NO STATE IS SAVED between postbacks. There are ways to retain state, such as the Session or Viewstate collections in ASP.NET, but as a rule of thumb write your programs where you can recreate your state on every postback.
This is probably the biggest difference between desktop and web-based application programming, and took me months to learn to the point where I was instinctively writing this way.
Postback happens when a webpage posts its data back to the same script/dll/whatever that generated the page in the first place.
Example in C# (asp.net)
...
if (!IsPostback)
// generate form
else
process submitted data;
Web developement generally involves html pages that hold forms (<form> tags). Forms post to URLs. You can set a given form to post to any url you want to. A postback is when a form posts back to it's own page/url.
The term has special significance for ASP.Net WebForms developers, because it is the primary mechanism driving a lot of the behavior for a page — specifically 'event handling'. ASP.Net WebForms pages have exactly one server form which nearly always posts back to itself, and these postbacks trigger execution on the server of something called the Page Lifecycle.
The term is also used in web application development when interacting with 3rd party web-service APIs
Many APIs require both an interactive and non-interactive integration. Typically the interactive part is done using redirects (site 1 redirects a user to site 2, where they sign in, and are redirected back). The non-interactive part is done using a 'postback', or an HTTP POST from site 2's servers to site 1's servers.
When a script generates an html form and that form's action http POSTs back to the same form.
Postback is essentially when a form is submitted to the same page or script (.php .asp etc) as you are currently on to proccesses the data rather than sending you to a new page.
An example could be a page on a forum (viewpage.php), where you submit a comment and it is submitted to the same page (viewpage.php) and you would then see it with the new content added.
See: http://en.wikipedia.org/wiki/Postback
Postback refers to HTML forms. An HTML form has 2 methods: GET and POST. These methods determine how data is sent from the client via the form, to the server. A Postback is the action of POSTing back to the submitting page. In essence, it forms a complete circuit from the client, to the server, and back again.
A post back is anything that cause the page from the client's web browser to be pushed back to the server.
There's alot of info out there, search google for postbacks.
Most of the time, any ASP control will cause a post back (button/link click) but some don't unless you tell them to (checkbox/combobox)
Yet the question is answered accurately above, but just want to share my knowledge .
Postback is basically a property that we can use while doing some tasks that need us to manage the state of the page, that is either we have fired some event for e.g. a button click or if we have refreshed our page.
When our page loads for the very first time , that is if we have refreshed our page, at that time postback-property is false, and after that it becomes true.
if(!ispostback)
{
// do some task here
}
else
{
//do another task here
}
http://happycodng.blogspot.in/2013/09/concept-of-postback-in.html

Resources