I CAN HAS CODE?!?
Jun
19
Posted in Annoyances by Michael at 23:40.

Sometimes I get annoyed with ASP.NET WebForms … No, make that greatly annoyed and disappointed with web forms.  As I mentioned in my last post, I was recently troubleshooting a 2nd incarnation of the mysterious multiple request syndrome (MMRS for short).  What made this time worse was what ending up being the cause.  In this case the request was being caused by a “url(none)” in a style attribute.  After tracking down the offending component I found something similar to the following example in the code.

Panel inner = new Panel();
inner.ID = "inner";
inner.Style.Add("background-image", "none");

Notice the last line.  Looks correct doesn’t it?  WRONG!  It’s not correct because WebForms Know Better Than You! ™.  When the above is rendered out to the page, it looks like this:

<div id="inner" style="background-image: url(none);"> </div>

Notice anythign wrong?  Yep, right there in the middle … the wonderful “url(none);” and a 2nd request in your browser for the “/none” path.  Well, poo… How did that get in there?  More importantly why did it get in there?  Especially considering the CSS spec specifically allows “none” as a value for the “background-image” property.  In fact the w3 page for the CSS1 (and CSS2) spec says “Value: <url> | none”.

Being the inquisitive sort, there was only one thing that I could do;  Fire up Reflector.NET and go to town.  First order of business was to find the Style property for the Panel control, which ends up being the Style property of the Panel’s base class, WebControl.  It is of type CssStyleCollection … My answer must lie somewhere in there.  The Add method in the CssStyleCollection class isn’t that special and just adds the items to some hash tables.  The Render methods might be interesting however.  After using the Analyzer on those and seeing how they are used we can determine two things.  First, the Render method that takes an HtmlTextWriter merely calls AddStyleAttribute on the writer and adds the CSS properties while the other one takes a CssTextWriter … Wait, what?  That’s a bit different.  It seems to call a WriteAttribute method of the CssTextWriter class.  After making our way to the static WriteAttribute method, we see the following:

if (key != ~HtmlTextWriterStyle.BackgroundColor)
{
    isUrl = attrNameLookupArray[(int) key].isUrl;
}
if (!isUrl)
{
    writer.Write(value);
}
else
{
    WriteUrlAttribute(writer, value);
}

Hmm, what is this “isUrl” and WriteUrlAttribute? Let’s go find out.  A quick Analyze on the “attrNameLookupArray” member shows that it is set in the static constructor so off we go.  In there we see a bunch of RegisterAttribute calls and we see one for the property we set at the beginning of this ordeal, “background-image”.  Digging into the RegisterAttribute method, we see that the last parameter to the function, which in the case of “background-image” is “true”, is the “isUrl” value we are looking for.  So the CssTextWriter considers the “background-image” attribute a URL based attribute … Makes sense, as it is one, so the issue must lie somewhere within WriteUrlAttribute.  Looking at the code for that function:

if (StringUtil.StringStartsWith(url, "url("))
{
    int startIndex = 4;
    int length = url.Length - 4;
    if (StringUtil.StringEndsWith(url, ')'))
    {
        length--;
    }
    str = url.Substring(startIndex, length).Trim();
}
// str is rendered out as "url(" + str + ")" after.

Well, that is unfortunately where are issue lies and there isn’t a damn thing we can do about it.  No special handling of “none”; Just a regurgitation of whatever we set the property to.  That is just too awesome.

Both comments and pings are currently closed.

Comments are closed.