The strangest bug of IE I’ve ever seen

We have a web application written in asp.net and we experienced really strange problem after recent modification. We have a strange behavior in IE9 with redirects and after some inspection we found a really strange fact (that almost make us lost 2 hours of work). To recreate this situation simply create a new page in an asp.net site, and put this code in it.

   1: <form id="form1" runat="server">

   2: <div>

   3:     <label id="queuecount"  />

   4:     <asp:ImageButton ID="ImageButton1" runat="server" />

   5:     <a href="http://www.microsoft.com">microsoft</a>

   6: </div>

   7: </form>

Now simply run this page with fiddler opened, you should see a simple broken image and a standard anchor tag. Now click on the link and look at what happened with fiddler.

image

Internet explorer issue the request to www.microsoft.com, but immediately after he request the original asp.ner page in POST. The order of the two requests varies, sometimes the test.aspx POST is done before requesting the link, and the user navigates to www.microsoft.com, but if the order is reversed (as appears in the above image) the user remains on the original page wondering on what is happening.

Using Firefox, Opera or Chrome do not produce any strange result, it seems only a bug of Internet Explorer. If you remove the HTML label tag or the image button everything works correctly, but it seems that if you have a label and an imagebutton, a simple anchor link in the page causes an unnecessary postback to the same page.

Gian Maria.

ASp.NEt handlers locked down in Windows 7 IIS

I’m configuring a site on a new virtual machine and when I browse to a site, IIS gives me this error

This configuration section cannot be used at this path. This happens when the section is locked at a parent level. Locking is either by default (overrideModeDefault="Deny"), or set explicitly by a location tag with overrideMode="Deny" or the legacy allowOverride="false".

I don’t know why, but on this Windows 7 virtual machine it seems that this section of the configuration is locked. If you find this error you can simply open an elevated permission command prompt, go to the C:\Windows\System32\inetsrv directory and type the commands

appcmd unlock config -section:system.webServer/handlers
appcmd unlock config -section:system.webServer/modules

and everything works again :)

Alk.

How to check if a user belong to a certain role in ASP.Net

This question is really simple to answer… or no? Suppose you need to verify, in a service, if the user belongs to the xxxx group, and then take a different path of execution if the condition is true.

if (Roles.IsUserInRole("xxxx"))

{

    ...

}

Ok, this seems such a piece of innocent code, but actually it caused me a bad bug. The reason is really simple, the same service is called from a program written in windows forms, (a windows service) and a web site. The programmer that is developing the web site, took the service and add that checks in one function, and I begin to get exception from the code of the service. The reason is clear Asp.Net roles and Membership are not configured in the windows program, nor I want to configure it.

To fix this, and in general to verify roles of the current user, when you does not know in advance if the code would be called  outside the context of a web application, we need to create the group xxxx in windows, assign the user that run the service or the program to this group and add this line at the very beginning of the winform program to use windows authentication.

AppDomain.CurrentDomain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal);

But this is not enough since the code in the service should not use the Roles.IsUserInRole() function because it needs to have membership configuration enabled. The solution is using this code instead of the above one.

var currentPrincipal = System.Threading.Thread.CurrentPrincipal;

if (currentPrincipal.IsInRole("xxxx")

This works because in windows forms the CurrentPrincipal is a WindowsPrincipal, and thus it checks if the current user belong to the group xxxx, but when it is run from a web site, with ASP.NEt membership configured, the principal is of type RolePrincipal as you can verify from Fgure1

image

Figure 1: the current principal of code running in asp.net sites with roles and membership configured is of type RolePrincipal.

and in this situation IsInRole() method verifies the user against ASP.Net roles.

Alk.

Deploy on remote machine during builds

Clearly Lab Management is really good to manage virtual environments and give a lot of flexibility on how to deploy your application on virtual machines, but if you do not have Lab Management you can still use the same technique to deploy application in remote computer during a build with the use of a simple scripts. The key is the ability to execute code on a remote computer with beyondexec or similar tool. Suppose you need to deploy an application called demo, you have a Tfs build called Demo, and you want to be able to deploy a specific build on a remote server, the solution could be this simple script

@echo off

set RemotePath= \\10.0.0.220\drops\demo\%1\_PublishedWebsites\Demo_Package\*.*
set LocalPath=c:\setup\demo

if exist %LocalPath% (
rmdir /s /q %LocalPath%
)
mkdir %LocalPath%

if not exist %RemotePath% (
echo remote path %RemotePath% doesn’t exist
goto Error
)

xcopy /c %RemotePath% %LocalPath%\.
%LocalPath%\Demo.deploy.cmd /Y

echo Demo Copied to LocalPath %LocalPath%
exit /b 0

:Error
echo Unable to Copy Demo Scripts
exit /b 1

The script is really simple, it simply compose the drop folder \\10.0.0.220\drops\demo with the single argument of the batch to find the path where the build had dropped the packages, then it creates a local directory where to copy all deploy plackage and run it.

Now you can store this script in source control, and use it with a tfs build, to deploy on a remote server, you can for example run from a command prompt:

beyondexecv2 \\10.0.0.220 -p "pa$$word” -c Deploy\DeployWeb.bat demo_20100607.3

This will copy the script on the 10.0.0.220 server, and launch the script with the argument demo_20100607.3 (the build number), here is the result.

BeyondExec V2.05 – Spawn Remote Processes on Windows NT/2000/XP WorkStations.
Copyright(C) 2002-2003 Craig.Peacock@beyondlogic.org
[10.0.0.220] Establishing Connection . . .
[10.0.0.220] BeyondExec service already installed on remote machine.
[10.0.0.220] Copying Deploy\DeployWeb.bat to \\10.0.0.220\ADMIN$\temp\DeployWeb.bat
[10.0.0.220] Command Successfully Issued to 10.0.0.220 on Pipe 1.
[win-y4onzs094up] Process started, ProcessID = 9780, ThreadID = 9788
\\10.0.0.220\drops\demo\demo_20100607.3\_PublishedWebsites\Demo_Package\Demo.deploy-readme.txt
\\10.0.0.220\drops\demo\demo_20100607.3\_PublishedWebsites\Demo_Package\Demo.deploy.cmd
\\10.0.0.220\drops\demo\demo_20100607.3\_PublishedWebsites\Demo_Package\Demo.SetParameters.xml
\\10.0.0.220\drops\demo\demo_20100607.3\_PublishedWebsites\Demo_Package\Demo.SourceManifest.xml
\\10.0.0.220\drops\demo\demo_20100607.3\_PublishedWebsites\Demo_Package\Demo.zip
5 File(s) copied
=========================================================
SetParameters from:
"c:\setup\demo\Demo.SetParameters.xml"
You can change IIS Application Name, Physical path, connectionString
or other deploy parameters in the above file.
——————————————————-
Start executing msdeploy.exe
——————————————————-
"C:\Program Files\IIS\Microsoft Web Deploy\\msdeploy.exe" -source:package=’c:\setup\demo\Demo.zip’ -dest:auto,includeAcls=’False’ -verb:syn
c -disableLink:AppPoolExtension -disableLink:ContentExtension -disableLink:CertificateExtension -setParamFile:"c:\setup\demo\Demo.SetParamet
ers.xml"
Info: Adding sitemanifest (sitemanifest).
Info: Updating createApp (Default Web Site/Demo_deploy).
Info: Adding contentPath (Default Web Site/Demo_deploy).
…
Info: Adding setAcl (Default Web Site/Demo_deploy).
Total changes: 37 (36 added, 0 deleted, 1 updated, 0 parameters changed, 737702 bytes copied)
[win-y4onzs094up] Process terminated with exit code 0 after 00:00:03.850s
[win-y4onzs094up] Removing C:\Windows\temp\DeployWeb.bat

As you can verify, the beyondexec tool was able to connect to remote machine, copied the deployweb.bat script on the remote machine and launched it with the right argument, now I can verify with IIS that the new web application was created in target machine.

image

Et voilà, we deployed a web application to a remote machine with a simple command. You can use this technique in a tfs build to deploy to a remote server.

Alk.

Asp net and an HiddenField inside a disable panel

I’ve hit a strange behavior of Hidden Field inside a disable asp.net panel, here is a simplified scenario that can reproduce my problem:

   1: <form id="form1" runat="server">

   2:    <asp:HiddenField ID="hf1" runat="server" />

   3:    <asp:TextBox ID="tb1" runat="server"></asp:TextBox>

   4:    <asp:Panel ID="Panel1" runat="server" Enabled="false">

   5:        <asp:HiddenField ID="hf2" runat="server" />

   6:        <asp:TextBox ID="tb2" runat="server"></asp:TextBox>

   7:    </asp:Panel>

   8:    <asp:Label ID="Label1" runat="server" Text="Label"></asp:Label>

   9:    <asp:Button ID="Button1" runat="server" Text="Button" />

  10:  </form>

This is a simple piece of code with two textbox, and two hidden fields, but the important aspect is that two of them are inside an asp:panel that has disabled=”true”. Then I have a label and a simple Button. Here is the code behind.

   1: Public Sub PageLoad(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

   2:      If (Page.IsPostBack = False) then

   3:          hf1.Value = "HF1"

   4:          hf2.Value = "HF2"

   5:          tb1.Text = "TB1"

   6:          tb2.Text = "TB2"

   7:      End If

   8: End Sub

   9:  

  10: Protected Sub Page_PreRender(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.PreRender

  11:      Label1.Text = "hf1=" & hf1.Value & "<br /> hf2=" & hf2.Value

  12: End Sub

The code set values for all controls in the pageLoad, only at the first call, while in PreRender I dump the content of the hiddenfield in a label to have a visual clue of what is happening. This is the page when it is loaded for the first time.image

Now I cause a postback pressing the Button, and the output become

image

While the two texboxes mantain the value that I set by code in pageLoad, the hidden field inside the disabled panel has lost his value. The key to understand this behavior is to have a first look with fiddler at the request issued when the button is pressed.

image

Clearly the browser send the content of the HTML Web Form and it sends only the value for enabled control, but how can the disabled textbox retain its value if the value is not passed with Request.Form parameters? The answer is: ViewState. Thanks to Web Developement Helper I can inspect viewstate

image

As you can verify the content of the Disabled textbox is placed in viewstate, so it can be restored during a postback, but for the hiddenField, the value is not present in the viewState so the value is lost between postback because it is disabled.

This is the problem I have in a control that I’ve developed, I use hidden field to communicate value to jQuery script, but when the user control is disabled, if I set a value by code in the hiddenField, value is null at the next postback, because the value is not passed with request.form nor it is inserted in the viewstate.

A solution to this problem can be found if you notice that even the first textbox does not have the text value stored in ViewState. This happens because the asp.net engine does not need it, because the value of the textbox can be retrieved from post parameters. Now if you add this handler to the code behind

   1: Protected Sub tb1_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles tb1.TextChanged

   2:     ischanged = true

   3: End Sub

the asp.net engine need to know if the user changed the value of the textbox to raise the event and the situation is really different. If you take a look at viewstate

image

value of Text property of the first texbox is now in the viewstate because asp.net engine needs it to understand when to raise textboxchanged event. This bring me the solution for hiddenField, because I can simply handle the event.

   1: Protected Sub hf2_ValueChanged(

   2:     ByVal sender As Object, 

   3:     ByVal e As System.EventArgs) Handles hf2.ValueChanged

   4: End Sub

Now asp.net insert the value of the Value property of HiddenField in the viewstate, because he needs to manage the ValueChanged event and the value of the HiddenField is persisted even if it is contained in a disabled Panel.

image

Alk.

Tags: