Extending/Inheriting classes to produce valid XHTML from ASP.NETv1.1

Discussion in 'ASP .Net' started by Anthony Williams, Feb 17, 2004.

  1. Morning all,

    I'm having a wee problem with a project I'm working on at the moment.
    I'm leading my company into producing a website, based upon Web
    Standards, which will be created using XHTML and CSS, and powered by
    ASP.NET.

    My first problem, which I'm near to solving, was that ASP.NET doesn't
    produce valid XHTML output. We don't want to spend money on third-party
    components, and we can't wait for ASP.NET 2.0, so we needed to find a
    way to use what we have to produce what we're after.

    I've taken to extending the System.Web.UI.Page and
    System.Web.UI.HtmlControls.HtmlForm controls (using Liquid Internet's
    methods, but converted to VB.NET, from
    http://www.liquid-internet.co.uk/content/dynamic/pages/series1article1.aspx)
    and after a couple of hiccups with events not firing, and changing
    Request.Path to Request.Url.ToString, I've managed to get everything
    working.

    Except that - if you take a look at the generated XHTML (which isn't
    valid yet by the way) - you'll find there is two hidden input fields
    called "__VIEWSTATE". One of them lives inside a <div> tag (valid
    XHTML), the other does not (invalid XHTML).

    Forgive me if I'm asking a question in the realms of newbie-dom, but
    I've no idea why two ViewState containers are being generated, and would
    really appreciate some help.

    For clarity, the default namespace in this project is "Listers.Group",
    and the assembly is called Listers.Group.dll.

    ' --- BEGIN CODE BLOCK - TestForm.aspx ---
    <%@ Page Language="vb" AutoEventWireup="false"
    Codebehind="listers.aspx.vb" Inherits="Listers.Group.Pages.Listers" %>
    <%@ Register TagPrefix="XHTML" Namespace="Listers.Group.XHTML"
    Assembly="Listers.Group" %>
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html>
    <head>
    <title runat="server" id=lgTitle>ListersGroup.co.uk - The largest
    privately-owned
    motor group in the Midlands!</title>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <meta name="MSSmartTagsPreventParsing" content="true" />
    <meta name="description" content="" id="lgDescription" runat="server" />
    <meta name="keywords" content="" id="lgKeywords" runat="server" />
    <link rel="stylesheet" type="text/css" href="inc/css/ListersAll.css"
    media="all" title="ListersGroup.co.uk" />
    </head>
    <body>
    <XHTML:Form id="ListersForm" method="post" runat="server">
    <div id="Page">
    <div id="Header">
    <h1>ListersGroup.co.uk</h1>
    <!-- A Custom Control normally lives here -->
    </div>
    <div id="Body">
    <div id="Navigation">
    <!-- A Custom Control normally lives here -->
    </div>
    <div id="Content">
    <!-- A Custom Control normally lives here -->
    <p>A button, to test viewstate and event firing:<br /><asp:button
    id="Button1" runat="server" Text="Button"></asp:button></p>
    </div>
    <div>
    <div id="Footer">
    <!-- A Custom Control normally lives here -->
    </div>
    </div>
    </XHTML:Form>
    </body>
    </html>
    ' --- END CODE BLOCK - TestForm.aspx ---

    ' --- BEGIN CODE BLOCK - XHTML.vb ---
    Imports System.Web
    Imports System.Web.UI
    Imports System.Web.UI.HtmlControls
    Imports System.Web.UI.WebControls
    Imports System.IO

    Namespace XHTML
    Public Class Page
    Inherits System.Web.UI.Page

    Public Sub New()
    ' ...
    End Sub ' New

    Protected Overrides Function
    LoadPageStateFromPersistenceMedium() As Object
    Dim Format As New LosFormatter
    Dim ViewState As String =
    Request.Form("__VIEWSTATE").Trim.ToString
    Return Format.Deserialize(ViewState)
    End Function ' LoadPageStateFromPersistenceMedium

    Protected Overrides Sub SavePageStateToPersistenceMedium(ByVal
    ViewState As Object)
    For Each c As Control In Me.Controls
    If c.GetType.ToString = "Listers.Group.XHTML.Form" Then
    Dim Format As New LosFormatter
    Dim Writer As New StringWriter
    Format.Serialize(Writer, ViewState)

    Dim StateContainer As New LiteralControl
    StateContainer.Text = _
    "<div id=""ViewStateContainer"">" & _
    "<input type=""hidden""
    name=""__VIEWSTATE"" value=""" & Writer.ToString & """ />" & _
    "</div>"

    c.Controls.AddAt(0, StateContainer)
    End If
    Next
    End Sub ' SavePageStateToPersistenceMedium

    End Class

    Public Class Form
    Inherits System.Web.UI.HtmlControls.HtmlForm

    Public Sub New()
    ' ...
    End Sub ' New

    Protected Overrides Sub RenderAttributes(ByVal Output As
    System.Web.UI.HtmlTextWriter)
    Output.WriteAttribute("id", Me.ID)
    Output.WriteAttribute("method", Me.Method)
    Output.WriteAttribute("action",
    HttpContext.Current.Request.Url.ToString)
    End Sub
    End Class
    End Namespace
    ' --- END CODE BLOCK - XHTML.vb ---

    Thanks in advance for any help!
    --
    Anthony Williams
    http://www.bigtone.net
    Anthony Williams, Feb 17, 2004
    #1
    1. Advertising

  2. Anthony Williams wrote:

    > Except that - if you take a look at the generated XHTML (which isn't
    > valid yet by the way) - you'll find there is two hidden input fields
    > called "__VIEWSTATE". One of them lives inside a <div> tag (valid
    > XHTML), the other does not (invalid XHTML).


    Allow me to direct you to a site where you can see the generated XHTML:
    http://dev.listersgroup.com/listers.group/listers.aspx

    Whoops! :eek:)

    --

    Anthony Williams
    BigTone Interactive
    http://www.bigtone.net
    Anthony Williams, Feb 17, 2004
    #2
    1. Advertising

  3. RE: Extending/Inheriting classes to produce valid XHTML from ASP.NET v1.1

    Hi Anthony,


    Thanks for posting in the community!
    From your description, you've implement a group of custom ASP.NET server
    controls which'll render out valid XHTML element and also, you 've override
    the certain methods which used to load and save viewstate so as to maintain
    the viewstate yourself. However, you found that the page's response content
    will contain two hidden field named "__VIEWSTATE", one is the one you
    manually generated which is valid and the other not. You're wondering what
    is the other one and how to avoid it,yes?
    If there is anything I misunderstood, please feel free to let me know.

    As for this this problem, I think it is a general behavior because the
    ASP.NET page will store and mantain the page's control's setting in a
    certain hidden field named "__VIEWSTATE", the content is encoded as base64
    format string. And when page is rendered out to client , the page's
    viewstate will be added into this field, also when the page posted back,
    the ASP.NET will retrieve back these infos and instantial it from this
    hidden field. The two method you've ovrride in your code:
    Protected Overrides Function LoadPageStateFromPersistenceMedium() As Object
    ................
    End Function ' LoadPageStateFromPersistenceMedium

    Protected Overrides Sub SavePageStateToPersistenceMedium(ByVal
    .....
    End Function

    Bydefault , the parent class (page class) will do these operations on
    viewstate. Since you've overrided the two method especially the
    SavePageStateToPersistenceMedium, and you didn't call the parent's method
    in your override method. The page won't set the hidden filed <input
    type="hidden" name ="__VIEWSTATE"...>. And because you've added another
    hidden field also named "__VIEWSTATE" , that's why you found there are two
    hidden field named "__VIEWSTATE" in the response content, do you think so?

    So as for your situation, you have implemented your own SERVER Controls and
    the Viewstate's Serializer and Deserializer, you manually write and
    retrieve the viewstate, the original "hidden" field is useless for you.
    However, this hidden field is added by ASP.NET's page class implicitly(when
    the page is rendered out to client), so we don't have any explicit
    interfaces to remove it unless we disable the viewstate(I think that's not
    what we want). How do you think of this?

    Here is a tech article discussing on the VIEWSTATE in ASP.NET
    #Taking a Bite Out of ASP.NET ViewState
    http://msdn.microsoft.com/library/en-us/dnaspnet/html/asp11222001.asp?frame=
    true

    Please check out the preceding suggestions and tell me your further
    requirement on this so as for me to do some further research to assit you.


    Regards,

    Steven Cheng
    Microsoft Online Support

    Get Secure! www.microsoft.com/security
    (This posting is provided "AS IS", with no warranties, and confers no
    rights.)

    Get Preview at ASP.NET whidbey
    http://msdn.microsoft.com/asp.net/whidbey/default.aspx
    Steven Cheng[MSFT], Feb 18, 2004
    #3
  4. RE: Extending/Inheriting classes to produce valid XHTML from ASP.NET v1.1

    Hi Anthony,


    I've searched for some further materials on the XHTML issue with ASP.NET
    page and control. Here is a good tech article which exactly discussing on
    this and provide some informative solutions. I'm not sure whether you've
    already read it before, here is the web link to it:

    #Valid XHTML within .NET
    http://www.liquid-internet.co.uk/content/dynamic/pages/series1article1.aspx

    I notice that it has implement a custom Form class(named Liquid:CustomForm)
    which derived from the ASP.NET HtmlForm Class , then we should use this
    custom form in ASP.NET web page rather then the normal <form> tag, for
    example:
    <%@ Page Inherits="Liquid.Tutorial.CustomPage" AutoEventWireup="True" %>
    <%@ Register TagPrefix="Liquid" Namespace="Liquid.Tutorial"
    Assembly="Liquid.Tutorial" %>
    <?xml version="1.0" encoding="utf-8"?>
    ...........................................
    <body>
    <Liquid:CustomForm
    id="myId"
    method="post"
    runat="server">
    <fieldset>
    <legend>Sample form</legend>
    <input type="submit"/>
    <asp:Literal
    id="inputViewState"
    runat="server"/>
    </fieldset>
    </Liquid:CustomForm>
    ............. </body>
    </html>


    Then, do you think it possbile to use this "Liquid:CustomForm" instead in
    your web pages?

    In addition to the above solution, I think there is still another means to
    manually modify the response content. We can use the Http Module in ASP.NET
    to do some modification on the certain request or response object. And the
    httpModule has serverl events such as
    BeginRequest.
    EndRequest
    PreSendRequestHeaders
    PreSendRequestContent
    And the "PreSendRequestContent" event signals that content is about to be
    sent to the client. This provides an opportunity to modify the content
    before it is sent.

    So I think you can take advantage of this event and manually remove the
    additional useless <input type=hidden name="__VIEWSTATE" ..> tag in the
    response's stream, do you think so?

    and here are some tech articles on using the response filter(httpmodule),
    the first one is exactly focus on the XHTML
    compliant:

    # Producing XHTML-Compliant Pages With Response Filters
    http://www.aspnetresources.com/articles/HttpFilters.aspx

    #Implementing Intercepting Filter in ASP.NET Using HTTP Module
    http://msdn.microsoft.com/library/en-us/dnpatterns/html/ImpInterceptingFilte
    rInASP.asp?frame=true


    Regards,

    Steven Cheng
    Microsoft Online Support

    Get Secure! www.microsoft.com/security
    (This posting is provided "AS IS", with no warranties, and confers no
    rights.)

    Get Preview at ASP.NET whidbey
    http://msdn.microsoft.com/asp.net/whidbey/default.aspx
    Steven Cheng[MSFT], Feb 18, 2004
    #4
  5. Steven Cheng[MSFT] wrote:

    > Thanks for posting in the community!
    > From your description...


    ....snip snip snippety snip...

    > ...which is valid and the other not. You're wondering what
    > is the other one and how to avoid it,yes?


    Yes, that's exactly what I'm doing.

    > As for this problem, I think it is a general behavior because the
    > ASP.NET page will store and mantain the page's control's setting in a
    > certain hidden field named "__VIEWSTATE", the content is encoded as base64
    > format string. And when page is rendered out to client , the page's
    > viewstate will be added into this field, also when the page posted back,
    > the ASP.NET will retrieve back these infos and instantial it from this
    > hidden field. The two method you've ovrride in your code:
    > Protected Overrides Function LoadPageStateFromPersistenceMedium() As Object
    > ...............
    > End Function ' LoadPageStateFromPersistenceMedium
    >
    > Protected Overrides Sub SavePageStateToPersistenceMedium(ByVal
    > ....
    > End Function


    I know. It's the general (default) behaviour that I'm trying to override
    here, because it generates invalid markup.

    > Bydefault , the parent class (page class) will do these operations on
    > viewstate. Since you've overrided the two method especially the
    > SavePageStateToPersistenceMedium, and you didn't call the parent's method
    > in your override method. The page won't set the hidden filed <input
    > type="hidden" name ="__VIEWSTATE"...>. And because you've added another
    > hidden field also named "__VIEWSTATE" , that's why you found there are two
    > hidden field named "__VIEWSTATE" in the response content, do you think so?


    Actually no, that's not it. I'm wondering why, when I've overridden the
    SavePageStateToPersistenceMedium method, it appears to fire the same
    method in the parent System.Web.UI.Page class.

    > So as for your situation, you have implemented your own SERVER Controls and
    > the Viewstate's Serializer and Deserializer, you manually write and
    > retrieve the viewstate, the original "hidden" field is useless for you.


    Not useless - just invalid.

    > However, this hidden field is added by ASP.NET's page class implicitly(when
    > the page is rendered out to client), so we don't have any explicit
    > interfaces to remove it unless we disable the viewstate(I think that's not
    > what we want). How do you think of this?


    Well, here's the clincher. I've previously tried to do this in C#, and
    it worked perfectly - something to do with the fact that, in C#, unless
    you explicitly call the parent's methods within your overridden method,
    they will not fire. I'm just wondering why this isn't the case with
    VB.NET (or maybe I'm wrong.)

    I don't want to disable ViewState, I simply want to make it persist to
    the page using valid XHTML, preferably using VB.NET (because that's what
    everyone else in my team is using) and within the same project.

    Thanks!
    --
    Anthony Williams
    http://www.bigtone.net
    Anthony Williams, Feb 18, 2004
    #5
  6. Steven Cheng[MSFT] wrote:

    > I've searched for some further materials on the XHTML issue with ASP.NET
    > page and control. Here is a good tech article which exactly discussing on
    > this and provide some informative solutions. I'm not sure whether you've
    > already read it before, here is the web link to it:
    >
    > #Valid XHTML within .NET
    > http://www.liquid-internet.co.uk/content/dynamic/pages/series1article1.aspx


    Cool... though I'm sure I've seen that link somewhere before...

    > Anthony Williams wrote:
    >
    >> I've taken to extending the System.Web.UI.Page and
    >> System.Web.UI.HtmlControls.HtmlForm controls (using Liquid Internet's
    >> methods, but converted to VB.NET, from
    >> http://www.liquid-internet.co.uk/content/dynamic/pages/series1article1.aspx)
    >> and after a couple of hiccups with events not firing, and changing
    >> Request.Path to Request.Url.ToString, I've managed to get everything
    >> working.


    Ah yes... that's where I saw it.

    > I notice that it has implement a custom Form class(named Liquid:CustomForm)
    > which derived from the ASP.NET HtmlForm Class , then we should use this
    > custom form in ASP.NET web page rather then the normal <form> tag, for
    > example:


    Steven, I've pretty much used the Liquid Internet method, except I've
    chosen to use VB.NET instead of C#, and because I'm the only member of
    my team who is using Visual Studio (everyone else is using Visual
    Basic.NET 2003) they would be unable to work on the project.

    If you check out the Liquid example, you'll see that the C# code does
    not implicitly call the parent method.

    > Then, do you think it possbile to use this "Liquid:CustomForm" instead in
    > your web pages?


    I'd rather use my own code, as I need to extend some other controls too.

    > In addition to the above solution, I think there is still another means to
    > manually modify the response content. We can use the Http Module in ASP.NET
    > to do some modification on the certain request or response object. And the
    > httpModule has serverl events such as
    > BeginRequest.
    > EndRequest
    > PreSendRequestHeaders
    > PreSendRequestContent
    > And the "PreSendRequestContent" event signals that content is about to be
    > sent to the client. This provides an opportunity to modify the content
    > before it is sent.


    If this is the only way to get around the implicit firing of the parent
    event, then I guess I shall have to go with it, but from my own
    research, I've found that this method is only useful for sites with
    small amounts of traffic - perforing a RegEx operation on a string
    everytime a page is requested seems like overkill - all I want to do is
    stop my method from implicitly calling the parent method.

    --
    Anthony Williams
    http://www.bigtone.net
    Anthony Williams, Feb 18, 2004
    #6
  7. Steven Cheng[MSFT] wrote:
    > Hi Anthony,
    >
    > I've created a small sample application(VB.NET). It contains one page,
    > using the Liquid class, and the page is use codebehind page. I change the
    > Liquid class, divede it into two parts. And now it could work. Since I
    > haven't other XHTML controls ,may be you can try adding some XHTML controls
    > onto it to see whether it works.


    Cool - the page works, but it's not doing it exactly as I want it to.

    The Liquid method requires that you place a Literal control onto the
    page - I don't want to do this, as this isn't the idea behind extending
    the Page class.

    Whilst my method also uses a Literal control, it creates the control
    programatically and inserts it at position 0 in the XHTML form's
    Controls collection.

    > In addition, I found that the VS.NET IDE will change the HTML source(aspx
    > page SOURCE) when you change from the Html view and design view of the
    > page, and that'll cause the page's source become invalid. So it is
    > recommend that you edit aspx page use text edit or just in html source.


    Yeah, this is something that - as a standards based designer - I've been
    aware of for ages. It's one of the most annoying things about VS' HTML
    editor, and I'll be glad when Whideby finally moves into a more stable
    release so that I can ditch 2002/2003 for good.

    > Please check out my sample page. Also, if you have got any further ideas ,
    > please also feel free to post here. Thanks.


    It works fine, but not as I need it to - I'd also be interested in how
    you managed to get the parent method of the Page to *not* fire, and not
    have the net result of two viewstate fields.

    I'll probably go and ask the bods in the m.p.d.f.a.buildingcontrols
    group (which I've only just found) to see if they know of any ways to
    explicitly override the parent methods - I don't want them firing
    implicitly as they are!

    Thanks for your help.
    --
    Anthony Williams
    http://www.bigtone.net
    Anthony Williams, Feb 20, 2004
    #7
  8. Re: Extending/Inheriting classes to produce valid XHTML from ASP.NET v1.1

    Hi Anthony,


    Thanks for your response. Yes, the Liquid class used a Literal Control to
    Contain the <input hidden > element for store viewstate. However, I think
    you can replace it with other controls( your custom XHTML controls), please
    try replace the Literal Control member of the Page CLASS in my sample with
    your own custom control, don't modify the other function to see whether it
    work. Also, as for how to let the page only display only one "<input
    type=hidden name="__viewstate" >" field, I think it is mainly due to that
    you must override the CustomForm class's RenderChild method. You may have a
    further view and check on the sample page or the Liquid form's class code,
    I believe you'll get the idea. Any way, hope you'll soon get the ideas you
    want.



    Regards,

    Steven Cheng
    Microsoft Online Support

    Get Secure! www.microsoft.com/security
    (This posting is provided "AS IS", with no warranties, and confers no
    rights.)

    Get Preview at ASP.NET whidbey
    http://msdn.microsoft.com/asp.net/whidbey/default.aspx
    Steven Cheng[MSFT], Feb 21, 2004
    #8
  9. Steven Cheng[MSFT] wrote:

    > Hi Anthony,
    >
    > Thanks for your response. Yes, the Liquid class used a Literal Control to
    > Contain the <input hidden> element for store viewstate. However, I think
    > you can replace it with other controls( your custom XHTML controls), please
    > try replace the Literal Control member of the Page CLASS in my sample with
    > your own custom control, don't modify the other function to see whether it
    > work.


    Yeah, I've chosen to use the literal control also, I'll happily post the
    code here when I'm done. I'm creating the control programatically as
    opposed to declaratively as shown in the Liquid method.

    > Also, as for how to let the page only display only one "<input
    > type=hidden name="__viewstate" >" field, I think it is mainly due to that
    > you must override the CustomForm class's RenderChild method.


    That sounds promising. I'll check it out - thanks for the direction!
    --
    Anthony Williams
    http://www.bigtone.net
    Anthony Williams, Feb 24, 2004
    #9
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Neo
    Replies:
    2
    Views:
    558
    bruce barker
    Aug 12, 2004
  2. Siegfried Heintze
    Replies:
    0
    Views:
    2,827
    Siegfried Heintze
    Nov 11, 2005
  3. Matthew Barnes
    Replies:
    0
    Views:
    365
    Matthew Barnes
    Nov 19, 2003
  4. Replies:
    5
    Views:
    449
    Luc The Perverse
    Oct 27, 2006
  5. Sherm Pendley

    did not produce a valid header

    Sherm Pendley, Jun 20, 2005, in forum: Perl Misc
    Replies:
    6
    Views:
    121
    Brian Wakem
    Jun 20, 2005
Loading...

Share This Page