An interesting problem was elevated to my desk recently.
An RSS feed written in asp.net was failing validation at http://validator.w3.org/feed/
The reason given was a missconfigured server.
After looking into this a little further i discovered the root of the problem was not a miss configured server it was a content length related issue.
IIS has two forms of compression, dynamic and static. Static content can be a jpg, a static html file or other such content that does not change and has a defined “size and shape”. where as asp.net pages and other such content are considrered dynamic.
Now, IIS when compressing static content knows the size of the object and hence passes the content length to the client in the header of the response stream, so the client knows how much is left to recieve.
If the content length is not passed down to the client then it is possible the client may get confused when it starts receiving all these chunks from IIS and doesnt when they are gong to stop inevitably leading to a splat.
This is also indicative of a response where .ContentLength = -1 so in other words the webserver is chunking the response.
Another important note is that IIS will only compress content to the client if the client has notified IIS it can accept compressed content, this is a header value buried in the header of the request.
However in this particuar instance it would seem that even though the validation engine was compatible with compression, it didnt like dynamic compression. Im unsure if this was a problem with the validation website or if this was an RSS compatibility requirement.
So in other words we have to provide IIS with the content length in order that it can send this information down to the client.
This is simple enough if you have ever needed to stream any type of content across any medium in .NET.
The current way the rss was being transmitted to the client was via the response.write method of the output response stream. This way may appear adequate in your development test browser (typically IE 7 or 8 ) and until you look deeper and apply lifecycle testing across all media you wont see that IIS isnt passing certain required information to the client (ie content length)
So a simple application of binary streaming should fix the problem.
To begin with the original code is correct to a point starting with setting the response type parameters like so
'Set response type
context.Response.ContentType = "application/rss+xml"
context.Response.ContentEncoding = Encoding.UTF8
so following on with the original code we create our TextWriter and pass it into our XmlTextWriter to populate with our XML feed
'Instantiate XML writer
Dim objStringWriter As StringWriter = New StringWriter()
Dim objXMLTextWriter As XmlTextWriter = New XmlTextWriter(objStringWriter)
now we can write our xml feed.
Once the xml feed is written we are ready to deposit the feed to the client. We are going to use the Response.BinaryWrite method of the response stream
'close the TextWriter
'send the xml generated down the response stream
Dim oStream As New MemoryStream(Encoding.UTF8.GetBytes(objStringWriter.ToString))
Dim buf As Byte()
ReDim buf(CType(oStream.Length, Int32) - 1)
oStream.Read(buf, 0, CType(oStream.Length, Int32))
Essentially what we have done is pull the xml text into a buffer of a specific size based on the xml length, and passed it directly to the BinaryWrite response method which in turn writes directly to the current httpcontext response buffer without character conversion. IIS knows then content length deduced from the binary buffer size and passes this information down to the client followed on with however many chunks of data until the transafer is complete.
this is the reflector of the binaryWrite method
public void BinaryWrite(byte buffer)
this.OutputStream.Write(buffer, 0, buffer.Length);
This type of response can also be applied to passing files down to a client request.
Using this approach removes the required “browse directory” permissions one needs to apply to the normal style virtual directory containing your static content such as pdf’s that you want made available for download.
This approach also allows you to hold all of your content in the same location (DB or file system) and you can apply rights to users accessing these files via .net rather than being restricted to NT authentication on the virtual directory simply by removing the need for teh virtual directory.