Back to Basics: Assert your assumptions and diff your source code
I've done a whole series of "Back to Basics" posts that I encourage you to check out. Sometimes I'll do a post as a result of a reader emailing me for help and this is one such post.
A person emailed me with an ASP.NET app was behaving differently on his computer vs. another developer's computer.
On his machine when he hit a protected page foo.aspx?returnurl=http://mymachine.domain.com
he would get a FORM element like this:
but on everyone else's machines their HTML was:
They debugging and were frustrated and eventually reached out. They said:
1. there's nothing going on in the aspx of login.aspx that would append the querystring.
2. there's nothing going on in the code-behind of the aspx that manipulates Form.Action or messes with the Page.Render in any way.
So, I'm stumped, because the querystring is included on my machine, but not on others. I've tried comparing IIS components, web.config differences, application pool runtime type, machine.config differences, possible differences in Modules for IIS (IISrewrite), but nothing is giving me love.
I suggested that they assert assumptions and start diffing everything. You can see in the last paragraph that they're comparing stuff but I think you really have to diff everything.
When something "works here but not there" my answer is always, what has changed? What's different? If the answer is "nothing is different" I'm just gonna say it again:
What are some things we can check?
- Do you know what's on disk?
- Do you know what ended up in memory? These are different things.
- There's local and machine-wide config to check
- Network Traffic
I had them do a sniff and see if there was a difference in HTTP traffic. My assumption was that the HTTP_REFERER HTTP header was different and there was some code that was causing the page to render differently.
We went back and forth over a few days and my reader became frustrated and just added this line in their app's Page_Load:
this.Form.Action = Request.Url.ToString();
Here they are basically reasserting the Form action by pulling it from the URL. It's gross and it's a hack. It's a Band-Aid on Cancer.
They then started looking at the source for ASP.NET proper and then decided to disassemble the code that was running on the other person's machine. They then started to assert their assumptions.
Is the code running what's on disk? For a compiled language, do the binaries reflect the source?
They looked in Temporary ASP.NET files at the compiled ASPX markup pages and found this.
__ctrl.Method = "post";
__ctrl.Action = "login.aspx";
What? Why is someone setting the FORM Action manually? And there's a line number.
They had diff compared all the source code but not the markup/views/html.
<form id="Form1" method="post" runat="server">
Other person's markup:
<form id="Form1" method="post" runat="server" action="Login.aspx">
The other person had hard-coded the action in their source markup. They'd been diffing everything but the markup.
When you are comparing two code-bases, make sure to compare everything or you might just lose a day or two like this person.
Thanks to my reader for sharing this and letting me in on this debugging adventure.
- Back To Basics: You aren't smarter than the compiler. (plus fun with Microbenchmarks)
- Back to Basics: Moving beyond for, if and switch
- Back to Basics: Dynamic Image Generation, ASP.NET Controllers, Routing, IHttpHandlers, and runAllManagedModulesForAllRequests
- Back to Basics: Daylight Savings Time bugs strike again with SetLastModified
- Good Exception Management Rules of Thumb - Back to Basics Edition
Sponsor: Big thanks to Red Gate for sponsoring the blog feed this week. Check out the Free Starter Edition of their release management tool! Deploy your SQL Server databases, .NET apps and services in a single, repeatable process with Red Gate’s Deployment Manager. Get started now with the free Starter Edition.