Thursday, April 30, 2009

Error : /ScriptResource.axd : Invalid viewstate.

This issue is caused when the ScriptResource.axd querystring parameters can not be decoded on the server. This error can be caused from multiple issues with server configuration or the Browser's interaction with the server. The ScriptResource.axd contains all of the clientside javascript routines for Ajax. Just because you include a scriptmanager that loads a script file it will never appear as a ScriptResource.AXD - instead it will be merely passed as the .js file you send if you reference a external script file. In other words it is what the Microsoft Ajax libraries inject into your HTML to allow them to access their javascript functions they need for page manipulation. ASP.NET will use the machine key to encrypt the ScriptResource.axd (and webresource.axd) url's parameters(in querystring), and by default the machinekey is a randomly generated one which may involve the current time. By default there is a different machinekey on every machine, and it changes when the application (w3svc.exe process) is recycled. If you are running a web farm you need to "hard code" the machinekey to be the same for every server. This way a response from one web server can be decrypted on another server. Like in the case one of your servers goes down for maintenance and the users traffic is routed to another server. You also need to "hard code" the machine key if you want to "survive" application recycles. Here is instructions for "hard coding" the machine key: http://msdn.microsoft.com/en-us/library/ms998288.aspx BUT WAIT.... This error can be caused from a number of different issues. One of which is having the wrong DOCTYPE for the style of page you are writing. Especially with Internet Explorer 8. This error can be caused from having a DOCTYPE of XHTML. This is because with XHTML all special characters should be encoded or all content should be wrapped inside a CDATA section. In other words if you don't have prefect XHTML in some cases the browser will not parse your XHTML correctly and the request to /ScriptResource.axd will have scrambled parameters Converting the DOCTYPE to HTML can solve the Viewstate issue.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
To This:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
Why does this solve the issue? The browser uses a different parsing algorithm which is "looser" and can handle the non-compliant XHTML that you might be outputting. One trick mentioned on the Internet to prevent the "Error : /ScriptResource.axd : Invalid viewstate." without having to change the DOCTYPE is to wrap your javascript in CDATA tags like this:
<script>    
    mycode;
</script>
would become:
<script>
// <![CDATA[    
     mycode;
// ]]>
</script>
Which is an attempt to get XHTML compliant. However, I have found that while this is good practice, there are probably other issues what will cause your HTML not be XMHTL compliant and changing DOCTYPES are the best policy. {6230289B-5BEE-409e-932A-2F01FA407A92}

Thursday, April 23, 2009

Disabling the OkControlId On A ModalPopupExtender

I am using the ModalPopupExtender Ajax extender in .NET to display a modal dailog that takes in some data and saves it to the database. The issue is that the saving the data to the database is a little slow and there is an oppurtunity for the user to press the "Save" button a couple of times before the modal dialog closes. This is because I am handling the OnClick event of the save button, which writes the data and then calls the Hide method of the ModalPopupExtender. It looks a little like this:
<asp:Panel ID="panel" runat="server" Style="display: none;">
    <asp:Button runat="server" Text="Save" Enabled="true" ID="saveButton" OnClick="saveButton_OnClick" />
    <asp:Button runat="server" Text="Cancel" ID="cancelButton" OnClick="cancel_OnClick" />
</asp:Panel>
<ajaxControlToolKit:ModalPopupExtender ID="ModalPopupExtender1" runat="server"
    PopupControlID="panel" TargetControlID="openButton" />
Code Behind:
protected void saveButton_OnClick(object sender, EventArgs e)
{
    ModalPopupExtender1.Hide();
    
    // Do Some Work That Takes Time
}
No matter how fast I can write the data, a round trip needs to happen before the modal dialog is closed. To solve this problem I added a little client side code that gets injected OnPageLoad to disable the button right away.
saveButton.OnClientClick = String.Format("this.disabled=true; __doPostBack('{0}','');", saveButton.UniqueID);
{6230289B-5BEE-409e-932A-2F01FA407A92}

Saturday, April 11, 2009

Validating and Email Address

Well I am doing it again, writing a form that validates a TextBox to figure out if it is an email address. If I had a ten cents for every time I have written this same for code in ISAPI, IDC/HTX, Classic ASP, ASP.NET and other languages I would be rich.

 

Once you have the input you need to validate that it really is an email address. There is no way to know for sure, since email is a forward only protocol. Some of the same I have done this in the past include:

  1. Check to make sure that there is a @ , which is pretty lame.
  2. Use a regular expression to check the email address, a little better.

Tonight I was thinking that it would be handy to get the MX record of the domain for the host of the email address. This way I would know if the host name accepted email (or at least the DNS administrator for that domain thought it accepted email) and I would also know that the domain exists and was returning DNS responses.

 

So search on the Internet for a C# query that would get me the list of MX records for the domain I found a article called: Build a C# DNS MX (Mail Exchange) Record Query Class  written by Peter A. Bromberg! I have actually met this guy he is pretty cool.

 

My code looks like this:

// WWB: Check To Make Sure The Email Address Parses
MailAddress mailAddress = null;
try
{
    mailAddress = new MailAddress(people.People_Email);
}
catch
{
    return;
}

// WWB: Check To Make Sure There Is a SMTP Server To Recieve The Email Address
if (DnsMx.GetMXRecords(mailAddress.Host).Length==0)
{
    return;
}

// WWB: Success 
{6230289B-5BEE-409e-932A-2F01FA407A92}

Friday, April 10, 2009

Handling Your SQLException By Number

I am working on a bug where I am getting this error: Source: .Net SqlClient Data Provider Description: The server failed to resume the transaction. It is a SQLException from SQL Server, that I want to try/catch in my C# code and handle. The nice thing about SQLException is there is a Number property that you can use to identify the error message from anyother SQL Error. The Number of this exception is 3971 So my C# code looks like this:
catch (SqlException sqlException)
{
    switch (sqlException.Number)
    {
        case 3971:
The Numbers come from the master.dbo.sysmessages table, one of the ways that I find out what number matches what message is be using a query like this:

SELECT *
FROM master.dbo.sysmessages 
WHERE description LIKE '%The server failed to resume%'
However, it is probably easier to use the debugger, that is if you can catch the error. In this case our bug reporting system was telling me the error, however it is hard to reproduce to "debug" the Number out of it. In that case I use the T-SQL above. {6230289B-5BEE-409e-932A-2F01FA407A92}

Friday, April 3, 2009

RadioButtonList Error With UpdatePanels

Let's consider this code for a minute:
<form id="form1" runat="server">
    <asp:ScriptManager runat="server" />
    <div>
        <asp:UpdatePanel runat="server" ChildrenAsTriggers="true">
            <ContentTemplate>
                <asp:RadioButtonList runat="server"
                ID="RadioButtonList1" AutoPostBack="true"
                OnSelectedIndexChanged="RadioButtonList1_SelectedIndexChanged">
                </asp:RadioButtonList>
            </ContentTemplate>
        </asp:UpdatePanel>
    </div>
</form>
Code behind:
protected void Page_Load(object sender, EventArgs e)
{
    if (!Page.IsPostBack)
    {
        String[] items = new String[] { "0", "1", "-10" };
        RadioButtonList1.DataSource = items;
        RadioButtonList1.DataBind();
        RadioButtonList1.SelectedValue = "0";
    }
}
Basically, we have a radio button list that databinds on the first request to the page and selects 0 as the selected value. This is inside an update panel, which means we can auto postback and record the radio button list change without having to refresh the page. The HTML source code ends up looking like this:
<table id="RadioButtonList1" class="dropdown" border="0" style="display: inline;">
<tr>
    <td><input id="RadioButtonList1_0" type="radio" name="RadioButtonList1" value="0" checked="checked" /><label for="RadioButtonList1_0">0</label></td>
</tr><tr>
    <td><input id="RadioButtonList1_1" type="radio" name="RadioButtonList1" value="1" onclick="javascript:setTimeout('__doPostBack(\'RadioButtonList1$1\',\'\')', 0)" /><label for="RadioButtonList1_1">1</label></td>
</tr><tr>
    <td><input id="RadioButtonList1_2" type="radio" name="RadioButtonList1" value="-10" onclick="javascript:setTimeout('__doPostBack(\'RadioButtonList1$2\',\'\')', 0)" /><label for="RadioButtonList1_2">-10</label></td>
</tr>
</table>
This code is autogenerated by the RadioButtonList control from .NET. Notice that Zero doesn't post back, why is this? Well the RadioButtonList control assumes that we don't have to know about the post back when it is the selected value. Howeever, this logic fails inside an Update Panel. Because the RadioButtonList's HTML doesn't refresh during the AysncPostBack, the zero radio button doesn't get a onlick client side event -- when we select value 1. In other words, this code no matter what you click on will never get a SelectedIndexChanged when zero is clicked. The solution is to call update on the Update Panel:
protected void RadioButtonList1_SelectedIndexChanged(object sender, EventArgs e)
{
    UpdatePanel1.Update();
}
{6230289B-5BEE-409e-932A-2F01FA407A92}