Multi-source cross page posting

Onion Blog

Syndication

Whenever I introduce the new cross-page posting features in ASP.NET 2.0 to students, one of the first questions that usually comes up is whether it is possible to post multiple pages to a single target page. A common scenario might be that you have several ways of collecting information from a user, but one final register / checkout / complete transaction page that should be shared by all source pages.
This is certainly easy enough to set up, the tricky part comes in accessing the previous page's type in the target page to extract the form values. For example, here's a sample source page that collects a client's name, age, and marital status. When submitted it will issue the POST request to Target.aspx (by setting the action of the form to that page) since we have specified a PostBackUrl property on the button that submits the page:
 
Enter your name: <asp:TextBox ID="_nameTextBox" runat="server" /><br />
Enter your age: <asp:TextBox ID="_ageTextBox" runat="server" /><br />
<asp:CheckBox ID="_marriedCheckBox" runat="server" Text="Married?" /><br />
<asp:Button ID="_nextPageButton" runat="server" Text="Next page" PostBackUrl="~/TargetPage.aspx" />
 
 
To make the values on this page accessible to the target page, it is common practice to define public properties in the code-behind file for the first page that return the values of the controls that will have already been populated from the POST body during the cross-page POST (ASP.NET evaluates the POST body using a new instance of the source page and executes its page lifecycle up to and including PreRender).
 
public partial class SourcePage1 : System.Web.UI.Page
{
  public string Name
  {
    get { return _nameTextBox.Text; }
  }
  public int Age
  {
    get { return int.Parse(_ageTextBox.Text); }
  }
  public bool Married
  {
    get { return _marriedCheckBox.Checked; }
  }
}
 
This works great for the case of one source page, as the target page can now cast the PreviousPage property to SourcePage1 and extract the values - or even better, use the PreviousPageType directive and strongly type the PreviousPage class to be SourcePage1, removing the need to cast at all:
 
<%@ PreviousPageType VirtualPath="~/SourcePage1.aspx" %>
 
And in the code behind file (assuming the presence of a Label with an ID of _messageLabel):
 
if (PreviousPage != null)
{
  _messageLabel.Text = string.Format("<h3>Hello there {0}, you are {1} years old and {2} married!</h3>",
        PreviousPage.Name, PreviousPage.Age, PreviousPage.Married ? "" : "not");
}
 
Now, if we introduce a second source page, also with the ability to collect the name, age, and marital status of the client, we run into a problem because each page is a distinct type with its own VirtualPath and the target page will somehow have to distinguish between a post from page1 and one from page2. One way to solve this is to implement a common interface in each source page's base class, so that the target page assumes only that the posting page implements a particular interface, and is not necessarily of one specific type or another. For example, we could write the IPersonInfo interface to model our cross page POST data as follows:
 
public interface IPersonInfo
{
  string Name { get; }
  int Age { get; }
  bool Married { get; }
}
 
In each of the source pages, we then implement the IPersonInfo on the code-behind base class, and our target page can now write:
 
IPersonInfo pi = PreviousPage as IPersonInfo;
if (pi != null)
{
  _messageLabel.Text = string.Format("<h3>Hello there {0}, you are {1} years old and {2} married!</h3>",
                                                   pi.Name, pi.Age, pi.Married ? "" : "not");
}
 
It would be even better if we could use the PreviousPageType directive to strongly type the PreviousPage property to the IPersonInfo interface, using the TypeName attribute as follows:
 
<%@ PreviousPageType TypeName="IPersonInfo" %> <!-- NOTE does not work -->
 
Unfortunately, the TypeName attribute of the PreviousPageType directive requires that the specified type inherit from System.Web.UI.Page (which seems too constraining if you ask me). You can introduce a work-around to get the strong typing by defining an abstract base class that implements the interface (or just defines abstract methods directly) and inherits from Page, as follows:
 
public abstract class PersonInfoPage : Page, IPersonInfo
{
  public abstract string Name { get; }
  public abstract int Age { get; }
  public abstract bool Married { get; }
}
 
However this requires that each of the source pages you author change their base class from Page to this new PersonInfoPage base, which may be asking too much if you already of a common Page base class you are using in your system. Here's an example of a code behind class for a source page using this new base class:
 
public partial class SourcePage1 : PersonInfoPage
{
  public override string Name
  {
    get { return _nameTextBox.Text; }
  }
  public override int Age
  {
    get { return int.Parse(_ageTextBox.Text); }
  }
  public override bool Married
  {
    get { return _marriedCheckBox.Checked; }
  }
}
 
and the code in the target page can now be written using the strongly typed PreviousPage property as follows:
 
<%@ PreviousPageType TypeName="PersonInfoPage" %>
 
and the corresponding code behind:
 
if (PreviousPage != null)
{
  _messageLabel.Text = string.Format("<h3>Hello there {0}, you are {1} years old and {2} married!</h3>",
                     PreviousPage.Name, PreviousPage.Age, PreviousPage.Married ? "" : "not");
}
 
After looking at all of the options, I would be inclined to use the interface-based technique, and just not bother with the PreviousPageType strong typing. You already have to check to see whether the PreviousPage property is null or not, and casting it to the interface using the 'as' operator in C# is about the same amount of work as checking for null. I was really hoping that I could specify an interface in the TypeName property, but since ASP.NET checks for a type that inherits from Page, that just won't work. It is nice to have the ability to post between pages again (this was not really possible in ASP.NET 1.1), and combined with a shared interface, it's another useful state propagation technique to keep in your toolbox.

Posted Oct 14 2005, 08:37 AM by fritz-onion
Filed under:

Comments

Sean Chase wrote re: Multi-source cross page posting
on 10-15-2005 12:19 PM
Very cool, thanks for sharing!
Mike wrote re: Multi-source cross page posting
on 10-15-2005 12:46 PM
Fritz,

Is there any way you know of to override the behaviour of a directive such as PreviousPageType so that you can implement it in a way that allowed an Interface?
Hussein Ahmad wrote re: Multi-source cross page posting
on 10-16-2005 2:14 PM
Dear Fritz, dont you think that interfaces(as you know) are putting more constrains on pages. for every page i have to implement may be some properties that i dont like to , but enforced to.
lets look on the problem from different side: if i have one procedure that handles button1.clik till button10.clik , why do i have to say again inside this procedure
if(the sender is buttonx) do this;
so you aggregate all of them in one place then separate them again .it is better in that case to have one proc for each handler .
same example in pages if i am going to aggregate all of them in one target.aspx i shouldnt think about know which page type is the source , otherwise make more than one target.aspx
what do you think ?
Fritz Onion wrote re: Multi-source cross page posting
on 10-17-2005 5:11 AM
Mike - I don't know of a way to override the behavior of a directive, no.

Hussein - I didn't mean to imply that this would be a common use-case, but I have seen scenarios where it made the most sense to build this way. In general, making more than one target page is probably the easiest way to go.
Christopher Steen wrote Link Listing - October 17, 2005
on 10-17-2005 9:34 AM
Aaron's HTTP.SYS transport running as LUA [Via: Keith Brown ]
An XML Guru's Guide to BizTalk Server...
Kevin Daly wrote re: Multi-source cross page posting
on 12-07-2005 9:42 AM
Sorry to come in so late, but I can give a concrete example where I recently used an interface to get around a single target page having two "from" pages: it was an application where at certain steps users could click an explicit "Previous Page" button (not the same as a browser back button).
This meant that certain pages could either be arrived at from a previous page in a wizard-like sequence, or from the following page.
Todd Lane wrote re: Multi-source cross page posting
on 01-25-2006 7:49 AM
Do you by chance have an example of this in VB.Net. I've tried following your C# code and can't see where I'm going wrong. I've implemented an Interface but when I post to the target page my Page object is always nothing. I've tried Server.Transfer and using the PostBackUrl property on the page and I get the same results with both.
Thanks
Tom Sioungaris wrote re: Multi-source cross page posting
on 12-18-2006 2:10 AM
Thanks Fritz, this technique is certainly very useful but the only thing I don't quite get is the need for the "PersonInfoPage" abstract class to implement the "IPersonInfo" interface. I noticed it in the book too and it striked me as a bit of an overkill. It seems to me that there's one abstraction too many since by introducing the abstract class to define the Name, Age and Married properties, the interface becomes redundant. We could instead set the "TypeName" property of the "PreviousPage" directive to the abstract class type and that's it. I know it's a very subtle thing but it makes the solution appear slightly less complicated. Let me know what you think. Thanks!
Fritz Onion wrote re: Multi-source cross page posting
on 12-22-2006 10:45 AM
Tom - yeah, using just an abstract class would certainly do the job, and simplify things you're right. I guess I went the interface route because that was how I first wanted to implement it...

-Fritz
Praveen wrote re: Multi-source cross page posting
on 05-10-2007 4:06 PM
Thanks a lot for sharing your knowledge. Saved me lots of time and effort.

Gratefully,
Praveen
xcell wrote re: Multi-source cross page posting
on 10-25-2007 1:48 AM
Thanks alot for your sharing. I save a lot of time.
Regards...
Samir Nigam wrote re: Multi-source cross page posting
on 11-18-2007 10:00 PM
Hi! i have say 1.aspx, 2.aspx, 3.aspx & finally final.aspx. in 1.aspx i collect first name & last name; in second page 2.aspx i collects mobile & email; & in 3.aspx i collect address. finally i want to collect all the information in final.aspx want to save in database. the work flow for this is: 1.aspx -> 2.aspx -> 3.aspx -> finall.aspx. how will i achieve this?
kral oyun wrote re: Multi-source cross page posting
on 11-28-2007 1:52 AM
I guess I went the interface route because that was how I first wanted to implement it
Vijay wrote re: Multi-source cross page posting
on 03-04-2008 8:20 PM
Thanks a lot..
I got idea about corss page posting very clearly
Oyun wrote re: Multi-source cross page posting
on 09-14-2008 5:08 AM

very thanks for you!! I got idea about corss page posting very clearly..

.NET:ASP wrote .NET:ASP.NET:Cross-Page Posting from Multiple Sources
on 10-20-2008 9:30 PM

<p><strong>SiteNavigation Solutions</strong></p> <p>Here is a <a target="_blank" href="www.pluralsight.com/.../10 ...

Add a Comment

(required)  
(optional)
(required)  
Remember Me?