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

A

Anthony Williams

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!
 
S

Steven Cheng[MSFT]

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
 
S

Steven Cheng[MSFT]

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
 
A

Anthony Williams

Steven said:
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!
 
A

Anthony Williams

Steven said:
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...

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.
 
A

Anthony Williams

Steven said:
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.
 
S

Steven Cheng[MSFT]

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
 
A

Anthony Williams

Steven said:
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!
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,482
Members
44,901
Latest member
Noble71S45

Latest Threads

Top