Monday, January 9, 2012

Windows 7 Home Premium and Visual Studio 2010

Just did a new install of Visual Studio 2010 on a Windows 7 Home Premium. After all the computer is not part of a domain, uses Home Networking, and I don't need any of the comparison features when checking out the different editions.
Well... almost true. It appears that Microsoft in their infinite wisdom decided that not only would they not offer up the .msi to manage Users and Groups, but they would ship it with Home Premium and then disable it from working. Friendly?
The problem I came across was that my newly installed system just wasn't playing well out of the box and it appeared to be a permissions problem (what a surprise!) Unfortunately, I tried to find out which users were enabled on the machine only to find out that you can't use the .msi gui interface to check up on them. Of course, behind the scenes everything is still working and you can use the command prompt (NET commands) to check up and change permissions.
Ultimately though, it was using the IntelliTrace break all option that set me on the right path.  It told me that my code could not be run because there were not sufficient permissions in the "Temporary ASP.NET Files" directory. Depending upon when I did the break and what had needed to be recompiled that time, the particular directory in question was either in the user's AppData/Local/Temp directory or the Windows\Microsoft.NET\Framework\v4.0.30319 directory.
Next I discovered that IIS normally runs (as in out of the box) in the context of IUSR. Although Windows 7 Home Premium disables the .msi manager, when you go to the directory and click sharing, if you know the user name (i.e. IUSR) it can be shared and access permissions granted to it.
Once I added the rights to IUSR for both the "Temporary ASP.NET Files" directories, things seemed to return to normal and my code could run as expected.

Friday, July 15, 2011

A potentially dangerous Request.Form value was detected from the client

The nanny state has definitely arrived in .NET 4.0 where all requests are not checked for possible invalid input, and in particular, HTML insertion into fields being entered into your form.  If you are lucky, you will first encounter this with a simple form and get the error message "A potentially dangerous Request.Form value was detected from the client" which at least gives you a hint at to what may be wrong.If you are unlucky, you may be using an UpdatePanel and just get the mysterious message "Microsoft JScript runtime error: Sys.WebForms.PageRequestManagerServerErrorException: An unknown error occurred while processing the request on the server. The status code returned from the server was: 500" which gives you no hint at all.

And if you are me, you are even more unlucky because you are simply updating a TextBox text field from a ListBox selected item which simply says "<No Value>" as the value and then get the update 500 message above when you do any-however unrelated-postback to the server.

The received solution to the problem used to be to set validateRequest="false" in the page tag at the top of the page. However, in .NET 4.0 you also need to set <httpRuntime requestValidationMode="2.0" /> as well to disable the validation.
But make certain that the entry is made in the WEB.CONFIG and do not attempt to use in the Web.Debug.Config or Web.Release.Config as it will not work.  The entry must be made in the <system.web> section.

The validateRequest can also be turned off globally in the WEB.CONFIG with a section <pages validateRequest="false" />.

There is an alternative approach suggested by www.track7.org in their article disabling request validation in asp.net 4.0 by creating a class:
using System;
using System.Web.Util;

class RequestValidatorDisabled : RequestValidator
{
    protected override bool IsValidRequestString(System.Web.HttpContext context, string value, RequestValidationSource requestValidationSource, string collectionKey, out int validationFailureIndex)
    {
        validationFailureIndex = -1;
        return true;
    }
}
and then adding a section

<httpRuntime requestValidationType="RequestValidationDisabled" />

to the WEB.CONFIG file in the <System.Web> section which overides the standard RequestValidation and substitutes your stub. The one advantage of this is that it will allow you to add back any validation that you feel is appropriate to you web pages.

Remember that Microsoft has been nannying you and once you have disabled these checks you must then add those of your own. When a tag is displayed in a TextBox it is not a problem but if you then use the text to update a label, then you can be allowing code insertion. Use Server.HtmlEncode() to ensure that no HTML text from the user is actually displayed on your web pages unintentionally.
Be careful.

Monday, July 11, 2011

ListBox jumps selected item to top - solution

When using a ListBox on an ASP.NET form using AutoPostBack the ListBox does not behave as expected:  when the form is posted back to the browser, not only is the rest of page updated but the ListBox itself is re-drawn by scrolling so that the currently selected item is now at the top of the ListBox. Initially this just appears to be a benign quirk, but when continually using forms using a ListBox it becomes extremely irritating.

This short tutorial demonstrates the behavior of a ListBox without the AutoPostBox-which works as expected-the behavior when AutoPostBack is enabled-which does not-and a straightforward cure that restores the original, expected, funtionality. This tutorial is written using Visual Studio 2010 with C# but the code is simple.

Create a ASP.NET Web Application for C# and replace the body content of Default.aspx with a ListBox:

<%@ Page Title="Home Page" Language="C#" MasterPageFile="~/Site.master" AutoEventWireup="true"
    CodeBehind="Default.aspx.cs" Inherits="ListBoxProblem._Default" %>
<asp:Content ID="HeaderContent" runat="server" ContentPlaceHolderID="HeadContent">
</asp:Content>
<asp:Content ID="BodyContent" runat="server" ContentPlaceHolderID="MainContent">
    <asp:ListBox ID="ListBox1" runat="server" Width="417px"></asp:ListBox>
</asp:Content>

The ListBox can be populated from any database table where there are more items to display than can be seen on within the display portion of the ListBox. To keep things simple, the Page_Load event of Default.cs in this example is updated to populate the ListBox with a static list of fruit, but the way it is populated is unimportant. Notice that it is only populated when there is not a postback event so that the list is not recreated when an item is created.

        protected void Page_Load(object sender, EventArgs e)
        {
            if (!IsPostBack)
            {
                ListItem[] data = { new ListItem("Apple"), new ListItem("Orange"), new ListItem("Banana"), new ListItem("Pear"), new ListItem("Apricot"), new ListItem("Grape"), new ListItem("Peach") };
                ListBox1.Items.AddRange(data);
                ListBox1.DataBind();
            }
        }
Run the project and play with the ListBox. This is a populated Listbox that works just as expected. When clicking any item, it is highlighted and the ListBox remains scrolled at exactly where it was; the scrollbars work but whichever item was highlighted remains in the same place after clicking it.



Often when a ListBox item is clicked the item becomes a reference to more data and the page needs to be updated with information based upon the item being clicked.  In this example, there will be a TextBox which is to be updated with the name of the fruit that has been clicked. In the real world, more complex information will then be updated.

Add a new TextBox to this page which it to be updated by when the ListBox is clicked.  Using the ListBox properties set AutoPostback to True which ensures that there is a round trip to the server when an event is triggered. In the ListBox events, double-click on the SelectedIndexChange event. This will add the name of the handler to the ASP code and switch to the code-behind C# code.

    <asp:ListBox ID="ListBox1" runat="server" Width="417px" AutoPostBack="True" 
        onselectedindexchanged="ListBox1_SelectedIndexChanged"></asp:ListBox><br /><br />
    <asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>

The SelectedIndexChanged event is automatically created in the C#  to run on the server. By adding a single line of code the TextBox can be updated with the selected value from the ListBox control.

        protected void ListBox1_SelectedIndexChanged(object sender, EventArgs e)
        {
            TextBox1.Text = ListBox1.SelectedValue;
        }

The expectation would be that the TextBox is updated and everything remained as before with the selected ListBox item remaining highlighted at the same position in the display window. Unfortunately, when the ListBox is clicked, not only is the TextBox updated but the item that has been selected within the TextBox is redisplayed at the top of the ListBox:

When it first happens, it is just a little surprising, but after a while most users find it extremely annoying. Fortunately, there is a simple fix by adding two UpdatePanels and the controlling ScriptManager to the web page. Each UpdatePanel controls an area of the web page that is to be updated following a postback event.

    <asp:ScriptManager ID="ScriptManager1" runat="server">
    </asp:ScriptManager>
    <asp:UpdatePanel ID="UpdatePanel1" runat="server" ChildrenAsTriggers="False" 
        UpdateMode="Conditional">
    <ContentTemplate>
        <asp:ListBox ID="ListBox1" runat="server" Width="417px" AutoPostBack="True" 
            onselectedindexchanged="ListBox1_SelectedIndexChanged"></asp:ListBox><br /><br />
    </ContentTemplate>
    </asp:UpdatePanel>
    <asp:UpdatePanel ID="UpdatePanel2" runat="server">
    <ContentTemplate>
        <asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
    </ContentTemplate>
    </asp:UpdatePanel>

The ScriptManager is just the standard "magic" to make the UpdatePanels work and needs no adjustment. The first UpdatePanel is placed around just the ListBox and the second UpdatePanel around the controls that are to be updated (in this case the TextBox). If the project is built and run at this point, then it will perform identically to before the panels were added.

But the first UpdatePanel must then be modified with two properties: UpdateMode must be set to Conditional and ChildrenAsTriggers must be set to False.  What this does is ensure that when the ListBox, as a child of the first UpdatePanel, tries to trigger an update (the default mode), the UpdatePanel does not respond to the event and so the ListBox remains untouched. Effectively the UpdatePanel round the ListBox absorbs the SelectedIndexChanged event from its' child and because the UpdateMode is set to Conditional, the UpdatePanel round the ListBox is not updated. At the same time the ScriptManager passes the Update event onto the other UpdatePanel on the page and it is updated; thus, the TextBox contained in the second UpdatePanel is updated with the selected value.

So finally, the application is back to behaving as expected. The one caveat is that you cannot update the ListBox as part of any ListBox event and expect that the browser will be automatically updated with the changes to the ListBox.