Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

TinyWebServer, an ideal portable webserver for ASP.NET project development

0.00/5 (No votes)
17 Nov 2007 1  
A tiny portable webserver, called TinyWebServer, which can be used wherever IIS is not availabe.

TinyWebServer : main window

Introduction

Have you ever wanted to show up an ASP.NET project where IIS was not accessible? Have you ever thought of if there can be a way to carry your web server wherever you go, i.e., on a USB flash stick or even a CD?

If so, then this cool TinyWebServer is for you! This tiny portable web server can be used for testing and developing ASP.NET projects, wherever IIS is not available.

Background

Very often, I had looked for a way to run an ASP.NET project without needing IIS to be installed. I had wondered how Microsoft Visual Studio 2005 could run its ASP.NET Development Webserver regardless of IIS. I tried more and more to find such a solution ... I made Google angry with my no-result searches, but still there was no solution. Therefore, I decided to find a way to write my own ...

As you know, VS2005 has a nice development server included, called "ASP.NET Development Server". If you look at how it actually does this, you'll find a console application named WebDev.WebServer.EXE located in your .NET 2.0 installation folder, which usually is "C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727". If you run it, you will see something like this:

ASP.NET Development Server

As you see, there are command-line options that can be set in order to run the ASP.NET Development Server on your specified folder. Well, seems to be okay, but there still are some issues remaining:

  • You should pass the parameters you specified whenever you want to run it again, or you should make a batch file to do it for you. There should be a better way!
  • Working with a console application such as this in a GUI-based platform is not so interesting. There should be a better way!
  • Although VS2005 finds a free and available port to run the web server for you, this console application will take it from a parameter you pass, which means the port you specify in your command line or batch file may not necessarily be available.
  • This console application uses a component called WebDev.WebHost.dll which is registered in the GAC (Global Assembly Cache). Since you won't see it and it won't be available in your search results, it can't be copied using XCOPY, as you might think!

What can we do then?

TinyWebServer at a Glance

The main part of the server is in a nice and tiny component named WebDev.WebHost.dll which we will try to reach. This tiny DLL is located in the following directory:

c:\WINDOWS\assembly\GAC_32\WebDev.WebHost\8.0.0.0__b03f5f7f11d50a3a\

While you try to reach to this path through Explorer, you will find out that Explorer can not easily show the folder due to an Explorer extension for GAC that gets installed while installing the Microsoft .NET framework.

So what? Easily try to reach this path using the command prompt? Found it? OK! Copy it to an accessible path and do the following ...

Start Microsoft Visual Studio 2005, create a new Windows Forms VB.NET project, add a reference to the DLL you copied, and create a class and name it WebSite.

Imports Microsoft.VisualStudio.WebHost
Imports System.IO
Public Class WebSite
    Inherits Server
    Implements IDisposable
' ...

This class I've inherited from Server, is the main class used for approaching the Web Server I was looking for. This class provides a constructor with these parameters: Port [the port you are going to use for your site], PhysicalPath [used for specifying the folder your site will be on], VirtualPath [which is used as your website virtual root], and Start and Stop methods to start and stop your service.

As you can see, the main idea and tool was what was mentioned above, all other things are done just for the GUI, finding a random available port, loading and saving configuration into an XML file, and etc.

Points of Interest

  • One of the things I encountered since developing is that the Server class which my WebSite class is inherited from has no writable properties to set the Port, PhysicalPath, and VirtualPath. They are all read-only properties!
  • But I needed to be able to change a particular website I've defined whenever I needed to. To solve this problem, I decided to create a shadow class named WebSiteData, which would be serializable and could contain all the properties from WebSite, and some other properties like a GUID, and a property named Enabled to store the started/stopped status of the website.

  • Another interesting thing is how I approached to find a random available port, and also checking the availability of a specified port:
  • Imports System.Net
    Imports System.Net.Sockets
    Public Class PortHelper
        Public Shared Function RandomPortAvailable() As Integer
            Dim _portAvailable As Boolean = False
            Dim _port As Integer = 0
            Dim _listener As TcpListener = Nothing
            Dim _rnd As New Random(Now.Millisecond)
            While Not _portAvailable
                _port = _rnd.Next(1001, 1999)
                Dim _ipEntry As IPHostEntry = _
                        Dns.GetHostEntry(Environment.MachineName)
                Dim _ipAddr() As IPAddress = _ipEntry.AddressList
                Try
                    _listener = New TcpListener(_ipAddr(0), _port)
                    _listener.Start()
                    _portAvailable = True
                    _listener.Stop()
                Catch ex As Exception
                    _portAvailable = False
                End Try
            End While
            Return _port
        End Function
        Public Shared Function IsPortAvailable(ByVal iPort As Integer) _
                As Boolean
            Dim _listener As TcpListener = Nothing
    
            Dim _ipEntry As IPHostEntry = _
                Dns.GetHostEntry(Environment.MachineName)
            Dim _ipAddr() As IPAddress = _ipEntry.AddressList
            Try
                _listener = New TcpListener(_ipAddr(0), iPort)
                _listener.Start() : _listener.Stop()
                Return True
            Catch ex As Exception
                Return False
            End Try
        End Function
    End Class

    TinyWebServer : properties window

  • And the thing is, I wanted to use the PropertyGrid object for my website properties dialog, so, I was looking for a way to enable a user to randomly find and select a free port through the PropertyGrid interface. As you can see, the UITypeEditor inherited class is the result.
  • Imports System.Drawing.Design
    Imports System.Windows.Forms.Design
    Imports System.ComponentModel
    Public Class PortEditor
        Inherits UITypeEditor
        Public Overrides Function GetEditStyle _
           (ByVal context As ITypeDescriptorContext) _
                As System.Drawing.Design.UITypeEditorEditStyle
            Return UITypeEditorEditStyle.Modal
        End Function
        Public Overrides Function EditValue(ByVal context As ITypeDescriptorContext, _
                ByVal provider As System.IServiceProvider, _
            ByVal value As Object) As Object
            Return PortHelper.RandomPortAvailable
        End Function
    End Class

    And a part of the WebSiteData class in which I defined the Port property:

    <Category("Service")> _
    <Description("Specifies the port, on which service will be available.")> _
    <Editor(GetType(PortEditor), GetType(System.Drawing.Design.UITypeEditor))> _
    Public Property Port() As Integer
        Get
            Return _port
        End Get
        Set(ByVal value As Integer)
            If PortHelper.IsPortAvailable(value) Then
                _port = value
                If _name.IndexOf("WebSite on Port:") > -1 Then
                    Me.Name = String.Format("WebSite on Port:{0}", _port)
                End If
            Else
                MessageBox.Show(String.Format("The port you specified, {0}, " & _
            "is busy by another process. try another.", value), _
                    "Alert", MessageBoxButtons.OK, MessageBoxIcon.Warning, _
                   MessageBoxDefaultButton.Button1)
            End If
        End Set
    End Property

History

  • Version 1.0.0.1: 17th Nov., 2007

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here