Post-Redirect-Get with ASP.NET
Solution 1:
Typically you would do this by making an aspx web form that uses the querystring to signal which record to load/process.
Let's say you have a page that let's you update some customer information:
http://www.mysite.com/customer.aspx
You would load the form using an id in the querystring:
http://www.mysite.com/customer.aspx?CustomerId=42
In the codebehind you would have something like this:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
int customerId = 0;
if (!string.IsNullOrEmpty(Request.QueryString["CustomerId"]))
{
int.TryParse(Request.QueryString["CustomerId"], out customerId );
}
if (customerId == 0)
{
//handle case when no valid customer id was passed in the qs here
}
else
{
//load customer details, bind controls etc
//make sure to handle the case when no customer was found using the id in the qs
}
}
}
Then somewhere in your page you would have a button that saves the changes. That button would have an OnClick handler in the code behind:
protected void SaveClicked(object sender, EventArgs e)
{
//save changes to database here
//Redirect if all went well
Response.Redirect("http://www.mysite.com/customer.aspx?CustomerId="
+ idOfSavedCustomer.ToString());
}
That should basically be it. The redirect will cause the browser to issue a new GET request for the url in the Redirect(...). It will load the page, the if (!IsPostBack)
will run and initialize the page with the new values you just saved in the previous post back.
For this whole process, the traffic between browser and server would look something like this:
Browser: GET http://www.mysite.com/customer.aspx?CustomerId=42
Server: 200 (send back some html)
Browser: POST http://www.mysite.com/customer.aspx?CustomerId=42 (post data sent in request)
Server: 302 (point to http://www.mysite.com/customer.aspx?CustomerId=42)
Browser: GET http://www.mysite.com/customer.aspx?CustomerId=42
Server: 200 (send html)
In the middle step, the server is basically saying:
"That post request you sent me, I'm done with that. Now please got to this other page here..."
The fact the url in fact referrs to the same page is not important.
Some musings in response to your bullet point list of questions:
- how can the perform a POST to a place that isn't its original form?
You can do this by setting the action
attribute on the form, or you can set the PostBackUrl
on the button.
- what becomes of the ViewState when you post to a form that doesn't read view state?
Depends. If you simply post the form to a different page, you can use the <%@ PreviousPageType .../> directive to tell the "new" page where the post came from. This will simplyfy working with the posted data on the new page. See this link for details.
- what becomes of the ViewState when you redirect to the "real" aspx web form?
View state is sent in the post request. When redirecting, the browser will load a new page and it will create it's own viestate.
- is ViewState fundamentally incompatible with ASP.net Post-Redirect-Get?
Depends on how you look at it. After the redirect the new page will not have access to the viewstate of the page before.
- is ASP.net fundamentally incompatible with Post-Redirect--Get?
No. See example above.
- how (i.e. what code) do you redirect to the "real" aspx web form?
Response.Redirect(url). This will send a response to the browser, telling it to do a new get request.
- when (i.e. in what event handler) do you redirect to the "real" aspx web form?
When you have performed all the work necessary to process the post request.
- the related questions raise issues of how you post form data. There is the implication that HTML forms cannot be used - and all form data must be added to the query string. Is this true? If so, why? If not, why not? Can a browser put form data in a query string?
Redirecting a post request is not well supported and should probably be avoided. It can be done (with some browser) by using the http response 307. When doing that, the server effectively tells the browser that "I will not process you post request, please post it to this other page instead".
- a related question mentions Server.Transfer. Using Server.Transfer is completely wrong, and in no way solves the Post-Redirect-Get problem (because there is no Redirect). Correct?
Server.Transfer(...) is something that is taking place on the server side. The browser is not aware of it. Basically a page can use Server.Transfer in order to have som other page do some processing, and that page will be responsible for sending a response back to the browser. But the browser will think that it was the original page the responded.
- what code change has to happen in the aspx or aspx.cs file to support PRG? Presumably, at the very least, the code must be changed to post somewhere besides MyPage.aspx.
No, a regular post back can be used. The trick is to have one (or a few) specific event handler(s) on the page which does a Repsonse.Redirect after processing the posted data.
Solution 2:
Q) how can the perform a POST to a place that isn't its original form?
A) With PRG, you don't POST to a different page, you post back to the same page (see the diagram on the wikipedia page you linked to.) But the response from that page MUST BE a 30X response (typically a 302.)
Q) what becomes of the ViewState when you post to a form that doesn't read view state?
A) The view state is there when you POST, but there the view state won't be there for the new page you are doing a GET on.
Q) what becomes of the ViewState when you redirect to the "real" aspx web form?
A) Per above, there is no more view state are redirecting to the page.
Q) is ViewState fundamentally incompatible with ASP.net?
A) ViewState is not incompatible with ASP.NET. It is (mostly) useless for P/R/G for rendering the page that you are redirected to.
Q) is ASP.net fundamentally incompatible with Post-Redirect--Get?
A) No - but you can't overly rely on using one page and keeping all your state in viewstate, as per above. That said, ASP.MVC is maps much better to P/R/G
Q) how (i.e. what code) do you redirect to the "real" aspx web form?
A) Response.Redirect("new_page_you_are_redirecting_to.aspx") in the bbLaunch_Click method of old_page_you_are_posting_from.aspx
Q) how (i.e. what url) do you redirect to the "real" aspx web form? A relation question mentions Response.Redirect(Request.RawUrl);
A) See above
Q) when (i.e. in what event handler) do you redirect to the "real" aspx web form?
A) After you've processed the button press, saved the data to DB (or session, etc), and before you've written anything else to the Response stream.
Q) the related questions raise issues of how you post form data. There is the implication that HTML forms cannot be used - and all form data must be added to the query string. Is this true?
A) No - the button press in ASP.NET WebForms will POST back to the page.
Q) If so, why? If not, why not?
A) It's simpler than this, is why not. Imaging two pages: first_page.asp and second_page.aspx. First_page.aspx has the button on it (along with other ASP.NET web controls, like text boxes, etc that the user has filled out.) When they press the button, a POST is made to first_page.aspx. After processing the the data (which is likely inside viewstate, though this is abstracted away), you redirect the user to second_page.aspx using Response.redirect. Second_page.aspx can display what you want. If you want (or need) to display UI that is similar to what was on first_page.aspx, including the controls and what they inputted, you would want to store that in the session, a cookie, the URL as querystring params, to set those controls on second_page.aspx. (But you may not need to display anything on second_page.aspx that is similar to first_page.aspx - so there is no general rule here.)
Q) Can a browser put form data in a query string?
A) Yes, if you set the method to GET instead of POST. You can't override WebForms to do this, and this isn't required for PRG
Q) a related question mentions Server.Transfer. Using Server.Transfer is completely wrong, and in no way solves the Post-Redirect-Get problem (because there is no Redirect). Correct?
A) Essentially
Q) what code change has to happen in the aspx or aspx.cs file to support PRG? Presumably, at the very least, the code must be changed to post somewhere besides MyPage.aspx.
A) The code should still post back (as mentioned above.) But then Mypage.aspx should re-direct to a new page in the button handler.