Tag Archives: Asp.net

Experiencing Orchard

A new post has been added to Learning in Public:

Off-topic: Experiencing Orchard

ASP.NET 1.1, IIS 6.0 and 64-bit Windows

A few days ago, one of the many distribution lists I belong to was presented with the following requests:

I’m trying to create a Web Service in Visual Studio .NET 2003 and am getting an error “Visual Studio .NET has detected that the specified Web server is not running ASP .NET version 1.1. You will be unable to run ASP .NET Web applications or services.”

The individual said that he had checked the script maps and everything seemed to be in order on the server.  They had installed and uninstalled the ASP.NET extensions several times using aspnet_regiis.exe.  After a few more communications the poster added:

(Potential complication: my machine is a 64-bit OS; does this change the equation?)

The answer is that running 64-bit Windows does have an affect on your ability to run ASP.NET 1.1 in IIS 6.  ASP.NET 1.1 only supports running in 32-bit mode.  Fortunately, IIS 6 on 64-bit Windows can run in either 64-bit mode or 32-bit mode.

The following steps to run IIS 6 in 32-bit mode can be found in our MSDN documentation:

  1. Click Start, click Run, type cmd, and then click OK.
  2. Type the following command to enable the 32-bit mode:

    cscript %SYSTEMDRIVE%inetpubadminscriptsadsutil.vbs SET W3SVC/AppPools/Enable32bitAppOnWin64 1

  3. Type the following command to install the version of ASP.NET 1.1 and to install the script maps at the IIS root and under:

    %SYSTEMROOT%Microsoft.NETFrameworkv1.1.4322aspnet_regiis.exe -i

  4. Make sure that the status of ASP.NET version 1.1.4322 is set to Allowed in the Web service extension list in Internet Information Services Manager.

After following these instructions, the issue still wasn’t resolved.  In fact, the script maps for the web application were not being properly updated.  I had the customer execute the “aspnet_regiis -ua” which would remove all versions of ASP.NET from the machine.  To reinstall the ASP.NET 1.1 again, you then need to reissue the “aspnet_regiis -i” command (use “aspnet_regiis -i -enable” if you are using Windows 2003).  This should allow you to run ASP.NET 1.1 on IIS 6.

Keep in mind, however, that IIS 6.0 cannot run in both 64-bit mode and 32-bit mode at the same time. By running IIS 6.0 in 32-bit mode on 64-bit Windows, ASP.NET 2.0 applications will also run in 32-bit mode.

Threading issue with VB.NET Default Instances

Here is an issue that showed up for one of our customers in the Microsoft forums for Visual Basic .NET.  It is NOT the typical ”cross-threaded UI update” issue that you might think. No, this one, IMO, is slightly harder to catch since no exception is thrown to let you know something has gone wrong.

One of the many new features of Visual Basic .NET are default form instances.  As the feature lists explain, a default form instance prevents you from having to “new up” an instance of a form before acting on it.  So, instead of using:

Dim frm As New frmMain
frm.Show()

I can simply use:

frmMain.Show()

This is handy, particularly for the folks coming from VB6 who are used to forms that behave in this manner.  However, default instances present a very interesting problem.

Take, for instance, a project that I create with a form (named frmMain) and a module (named BackgroundMethods.vb) .  For the form, I have simply added a multi-line text box (named txtOutput) and a button control (named button1). 

Here is the code I have in my project:

[frmMain]

Imports System.Threading
Public Class frmMain
  Private Sub Button1_Click( ByVal sender As System.Object, _
                             ByVal e As System.EventArgs) _
                             Handles Button1.Click
     Dim t As Thread = New Thread(AddressOf GetData)
     t.Start()
     txtOutput.Text &= "Updates complete"
     ' Break after the call above to read the value
     ' in txtOutput.Text
  End Sub
End Class

[BackgroundMethods.vb]

Imports System.Threading
Module BackgroundMethods
   Public Sub GetData()
      WaitForData("Message 1")
      WaitForData("Message 2")
   End Sub
   Public Sub WaitForData(ByVal strMessage As String)
      ' Presumably this method would actually be
      ' waiting for data from a network connection,<
      ' serial port, or other source
      Thread.Sleep(2000)
      My.Forms.frmMain.txtOutput.Text &= (vbCrLf & Now().ToShortTimeString() & _
      vbTab & strMessage)
      ' Break after the call above to read the value
      ' in My.Forms.frmMain.txtOutput.Text
   End Sub
End Module

So the simple example is that I have a button which, when clicked, will execute the “GetData” method asynchronously in a module.  That method is going to call the WaitForData method that updates the UI with two different messages (“message1” and “message2”).  WaitForData is supposed to simulate a long-running process, so I threw in the typical “thread.sleep” call to make this illusion. 

If you run this code, you will notice that no exceptions are thrown, but the UI for your form is also not updated.  Why is this?  You would have at least expected a cross-thread exception, right?

In any other managed language, this likely wouldn’t happen — namely because the “My” application is specific to VB, as well as default form instances!  In C#, if I try to update the UI from another thread, I would get an exception stating: “Cross-thread operation not valid: Control ‘txtSerialIn’ accessed from a thread other than the thread it was created on.” which could be solved by using the “Invoke” method.   

The issue with Visual Basic, in this instance, is that the default form instances are thread-specific.  So, when I try to access the form using My.Forms.frmMain from within the worker thread, a NEW default instance is created under the covers.  My calls to update the text box are then executed on the NEW instance of the form which resides in the same thread as the call to update it — hence it doesn’t throw a cross-thread exception. In the mind of the VB program, the request to update the textbox occurred without an error.  When the worker thread dies, the second instance of the form (which was never displayed) is now a candidate for garbage collection.  Meanwhile, back on the original thread and original form the textbox is left blank.  You can validate this by running the program (I have attached sample code to this blog post) and setting breakpoints on the textbox update line in the WaitForData method, and in the last line of the button1_click event handler of the code.  You will notice that after the second call to WaitForData (before the debugger exits the Sub) that My.Forms.frmMain.txtOutput.Text has been properly set to the value you expected.  However, remember that this is on a second background instance of the form, not the original one you expected.  Once the debugger hits the last line in the button1_click event handler, read the value of txtOutput.Text and realize THAT instance of the textbox was never updated.

So what is the solution?

First off, you still have to use the “Invoke solution” that is often times bandied about in threading discussions.  To do this in VB.NET (and particularly in our solution), do the following:

1. Add the following code to the top of your BackgroundMethods.vb file:

Delegate Sub UpdateTextHandler(ByVal strMessage As String

This allows you to create a delegate that can be invoked on the UI.

2. Add the following method to your frmMain file:

Public Sub UpdateTextMethod(ByVal strMessage As String)
   txtOutput.Text &= (vbCrLf & Now().ToShortTimeString() & vbTab & strMessage)
End Sub

This creates the method that will actually be executed via your delegate from the worker thread.

3. Change your WaitForData method as follows:

Public Sub WaitForData(ByVal strMessage As String)
    ' Presumably this method would actually be
    ' waiting for data from a network connection
    ' serial port, or other source
    Thread.Sleep(2000)
    Dim f As frmMain = My.Application.OpenForms("frmMain")
    f.Invoke(New UpdateTextHandler(AddressOf f.UpdateTextMethod), _
             New Object() {strMessage})
End Sub

This method now uses the form’s “Invoke” method (actually defined in Control) to execute UpdateTextMethod on the original form via the UpdateTextHandler delegate.

So what is happening is that your new thread is getting an instance to the existing frmMain instance by going through the OpenForms call.  Once I have that instance, I can invoke a delegate that points to the “UpdateTextMethod” of the existing form ( passing in the message in the object array ).  By invoking, I am able to get back on the UI’s thread and that call can execute any updates to the UI that it wishes.

Keep this in mind the next time you are not receiving errors and your UI isn’t getting updated how you would expect — particularly if you code communicates with the network, a serial device, or other device which communicates asynchronously.

ASP.NET 2.0 Quickstarts Available

For those of you that don’t know, the ASP.NET 2.0 SDK quickstarts are available.  Obviously, these are just an overview, but it helps to get yourself up and running fairly quickly with features new and old.

Check them out at http://quickstarts.asp.net/QuickStartv20

File uploading in a web environment

A recent question was asked on the ASP.NET forums:

“i’m building a page to let people upload images to my site. they are supposed to see the images after uploading them.
i wondered if somebody can take ane “exe” file, change the extension to “jpg”, upload it, and then run it by pressing the “view picture” button. will my server run this exe file? if yes, how can i check if it image (“jpg” and “gif”) or something else?
great thanks…”

The question actually encompasses a very frequent request that users have. The fact that someone knew to ask about this before just implementing the upload feature proves that the mentality toward securing applications has been changed slightly from “Lets implement as many features as we can” to “How will implementing this feature affect the security of my application”.  This mentality, I feel, is spurred by several factors such as Microsoft’s increased Trustworthy Compupting initiative.

Since I feel its good to reward people for thinking about security first, I will do my best to answer this question for the user here on my blog. In the next few days, I will be launching a series of posts relating to uploading files in a web environment, the security issues, and better ways to implement the feature.  I’ll start by defining the functionality that is ultimately wanted, provide some insight into the various ways to implement this functionality and the security issues surrounding each approach, and then move on to designing a solution and perhaps even provide some sample code.

For now, let’s focus on the functionality and delve a bit into some various ways to implement this feature.

In general, the developer wants users to be able to upload image files to a website, and let someone or several people view the images after they are uploaded. This feature is implemented in the very software that is used to run this blog — Community Server.  Over the years, this feature has been implemented in more ways than I care to count.  Some folks store the uploaded file as is to the file system.  Others have stored the binary data as a BLOB in a database.  Others have used hybrids of this mechanism.  For this portion of the article, we will focus on a file-based approach and follow up with a database approach.

Storing in the File System

The most logical way to store files, it would seem, is in a file system.  From a public internet standpoint, however, one has to consider the trade offs of this approach.  The first problem is that your web user account (most likely the ASPNET account) has to have permission to write to the file system in order to pull this off.  The second issue is that if you write to a file within the scope of your web’s root folder, those files can most likely be accessed through IIS as well (and since this particular user desires for the images to be available to the public, they almost have to be available).  The security concerns are massive.  A user could upload a web-executable script to the server that they could then use as a trojan to gain access to the rest of the server. More advanced hacks could be used to compromise memory buffers and cause an executable to run in the server process (one of the main resons behind the new aspnet_wp running under the context of a low-privileged user).  There are some ways to decrease the risk involved in this method, however.  Some of them involve security through obscurity (not sufficient by itself).  Some of them involve coupling the best of OS security, web security and application security. 

Directory Structure

For starters, consider the fact that you do not want any files that are uploaded to be scriptable on the server side.  So lets set up a directory structure and security for our saved files. Start by creating your main upload directory outside of the web root.  For example, if your web root is found at C:inetpubwwwroot , create your image directory at C:inetpubuploadroot.  So why did we do this?  This prevents anyone from uploading malicious scriptable code to your server that can be executed on the server.  Once you create your directory, make sure you grant read and write permission to ASPNET user (if you are not using impersonation)  or to the Groups and Users which you will allow to upload files.  In my case, I granted the following permissions:

Administrators      Full Control
ASPNET             List Folder Contents, Read, Write
Network Service  List Folder Contents, Read, Write
System                 Full Control

Uploading your File

Once you have set up your directory structure, you’ll need to create your upload page. You only need an HTML file control and a submit button. Once you add your HTML controls, make sure you run them at the server side.

screenshot

Once you’ve set up the page, add the following code to save the file:

private void btnSubmit_Click(object sender, System.EventArgs e) {
 HttpPostedFile file = fleUpload.PostedFile;
 if( file != null ) {
     string serverFilePath = String.Format(   
        @"C:domainstitus.touploadroot{0}",
        file.FileName.Substring( 
        file.FileName.LastIndexOf(@"") ) ); 
        // TODO: Write file validation routine.
        if( ValidateIsJpeg( file ) ) {
           file.SaveAs( serverFilePath );
        }
  }
}

Validating The File

This get’s the job done for uploading, but it still isn’t secure and we haven’t given the user any way to retreive the file.  Now, I’m not an expert in image file types, but I know that each has a format.  I would HIGHLY recommend that you learn the proper methods to validate each file type you intend to accept and write a routine to test the uploaded file against the expected format.  For JPEG files, you can read an online FAQ at http://www.faqs.org/faqs/jpeg-faq/ that will explain the format and give you clues on how to validate this file.   Remember that ALL INPUT IS EVIL and with file uploading, this is particularly important.  However, I’ll leave this implementation up to you since this can get rather complex and will change based on each file type you want to accept. 

In Part #2, we’ll discuss how to retreive images that are stored on the file server using an HttpHandler.

Forms Authentication Cookies in the QueryString

Most folks don’t like their authentication data appearing in the query string, and with good reason. However, one does have to consider some trade offs when enabling cookieless sessions.

A user recently posted the following in an ASP.NET security forum.:

I use Forms Authentication technique in my Web application interactive with mobile devices. The configuration is like the following:

 < authentication mode="Forms" >
   < forms loginUrl="login.aspx" timeout="30" protection="All" path="/" />
 </ authentication >
 < authorization >
   < deny users="?" />
 < /authorization >
 < sessionState mode="InProc" 
      stateConnectionString="tcpip=127.0.0.1:42424" 
      sqlConnectionString="data source=127.0.0.1;Trusted_Connection=yes" 
      cookieless="true" timeout="20" />

Mangled URLs are used during sessions due to the cookieless=true setting. But why is the authentication cookie (in my case, its name is ASPXAUTH) also carried in the URIs? I know that this cookies is needed to be present in HTTP headers, but what configuration has defined this cookie is embedded in the query string of the URL like this?

http://localhost/myapp/(wcaz3svlxsdfinygyttuiu45)/default.aspx?__ufps=594900&.ASPXAUTH=887134660EC8D9CE8D72

The answer is simple but again requires you to consider the trade-offs when using cookieless sessions. This behavior is largely in part because the SessionStateModule class writes data to the cookies collection using HttpRequest.AddResponseCookie()

The AddResponseCookie() method looks to see if the cookie collection is null (and it will be if you are using cookieless sessions). If it is null, it will then append the asp.net auth cookie to an internal HttpValueCollection. These values are then written to the QueryString when the handler writes the response back to the user.

The fact that this is an cookie doesn’t go away because it’s a “special cookie”. In fact, what good would your cookie do if it was, in fact, written back in the header? The whole reason behind cookieless sessions is to allow sites to work that don’t support client-side cookies. If someone didn’t support cookies, and your authentication cookie was written back in the header instead of the QueryString, your cookie-based forms authentication cookie wouldn’t work either.

Keep this in mind when enabling cookieless sessions and forms authentication together.