65.9K
CodeProject 正在变化。 阅读更多。
Home

TinyWebServer,ASP.NET 项目开发的理想便携式 Web 服务器

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.61/5 (18投票s)

2007年11月17日

CPOL

4分钟阅读

viewsIcon

126976

downloadIcon

8230

一个名为 TinyWebServer 的小型便携式 Web 服务器,可在 IIS 不可用之处使用。

TinyWebServer : main window

引言

您是否曾想过在 IIS 不可用的情况下展示 ASP.NET 项目?您是否曾想过是否有一种方法可以将您的 Web 服务器随身携带,例如放在 USB 闪存驱动器甚至 CD 上?

如果是这样,那么这款很棒的 TinyWebServer 就是为您准备的!这款小型便携式 Web 服务器可用于在 IIS 不可用的地方测试和开发 ASP.NET 项目。

背景

我经常寻找一种无需安装 IIS 即可运行 ASP.NET 项目的方法。我曾想知道 Microsoft Visual Studio 2005 如何运行其 ASP.NET Development Webserver 而不受 IIS 的限制。我尝试了更多来寻找解决方案……我让 Google 因我的搜索无结果而生气,但仍然没有解决方案。因此,我决定找到一种编写自己的方法……

如您所知,VS2005 包含一个名为“ASP.NET Development Server”的优秀开发服务器。如果您查看它的实际工作原理,您会在 .NET 2.0 安装文件夹中找到一个名为 WebDev.WebServer.EXE 的控制台应用程序,通常位于“C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727”。如果您运行它,您会看到类似这样的内容

ASP.NET Development Server

如您所见,有一些命令行选项可以设置,以便在您指定的文件夹上运行 ASP.NET Development Server。好吧,看起来不错,但仍然存在一些问题

  • 每次想再次运行时,您都应该传递指定的参数,或者您应该创建一个批处理文件来为您执行此操作。应该有更好的方法!
  • 在基于 GUI 的平台上使用像这样的控制台应用程序并不那么有趣。应该有更好的方法!
  • 尽管 VS2005 会找到一个免费可用的端口来为您运行 Web 服务器,但此控制台应用程序会从您传递的参数中获取它,这意味着您在命令行或批处理文件中指定的端口不一定可用。
  • 此控制台应用程序使用一个名为 WebDev.WebHost.dll 的组件,该组件已在 GAC (Global Assembly Cache) 中注册。由于您看不到它,并且它不会出现在您的搜索结果中,因此它无法像您可能认为的那样使用 XCOPY 复制!

那么我们能做什么呢?

TinyWebServer 概览

服务器的主要部分是一个漂亮的小组件,名为 WebDev.WebHost.dll,我们将尝试访问它。这个小 DLL 位于以下目录

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

当您尝试通过 Explorer 访问此路径时,您会发现 Explorer 由于安装 Microsoft .NET 框架时安装的 GAC 的 Explorer 扩展而无法轻松显示该文件夹。

那又怎样?很容易尝试通过命令提示符访问此路径?找到了吗?好的!将其复制到可访问的路径并执行以下操作……

启动 Microsoft Visual Studio 2005,创建一个新的 Windows Forms VB.NET 项目,添加对您复制的 DLL 的引用,然后创建一个名为 WebSite 的类。

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

我继承自 Server 的这个类,是用于访问我正在寻找的 Web 服务器的主要类。该类提供了一个带以下参数的构造函数:Port [您将用于您站点的端口]、PhysicalPath [用于指定您的站点所在的文件夹]、VirtualPath [用作您的网站虚拟根],以及用于启动和停止服务的 StartStop 方法。

如您所见,主要思想和工具就是上面提到的,所有其他事情都是为了 GUI,查找随机可用的端口,加载和保存配置到 XML 文件等等。

关注点

  • 在我开发过程中遇到的一个问题是,我的 WebSite 类继承的 Server 类没有任何可写属性来设置 PortPhysicalPathVirtualPath。它们都是只读属性!
  • 但我需要能够在我需要时更改我定义的特定网站。为了解决这个问题,我决定创建一个名为 WebSiteData 的影子类,该类是可序列化的,并且可以包含 WebSite 中的所有属性,以及一些其他属性,如 GUID 和一个名为 Enabled 的属性来存储网站的启动/停止状态。

  • 另一个有趣的事情是我如何找到一个随机可用的端口,以及如何检查指定端口的可用性
  • 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

  • 我的想法是,我想为我的网站属性对话框使用 PropertyGrid 对象,所以我正在寻找一种方法来使用户能够通过 PropertyGrid 界面随机查找并选择一个空闲端口。如您所见,UITypeEditor 继承类就是结果。
  • 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

    以及我定义 Port 属性的 WebSiteData 类的一部分

    <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

历史

  • 版本 1.0.0.1:2007 年 11 月 17 日
© . All rights reserved.