我有同样的问题,但没有使用卡西尼号。相反,我有自己的网络服务器托管基于System.Net.HttpListener
通过 ASP.Net 支持System.Web.HttpRuntime
在通过创建的不同应用程序域中运行System.Web.Hosting.ApplicationHost.CreateApplicationHost()
。这本质上就是 Cassini 的工作方式,只不过 Cassini 工作在套接字层并实现了许多由System.Net.HttpListener
itself.
无论如何,为了解决我的问题,我需要打电话System.Web.HttpRuntime.Close()
在让 NUnit 卸载我的应用程序域之前。我通过暴露一个新的Close()
我的主机代理类中的方法,由我的 [SetupFixture] 类的 [TearDown] 方法调用,并且该方法调用System.Web.HttpRuntime.Close()
.
我通过 .Net Reflector 查看了 Cassini 的实现,尽管它使用System.Web.HttpRuntime.ProcessRequest()
,好像没有调用System.Web.HttpRuntime.Close()
任何地方。
我不太确定如何继续使用预构建的卡西尼实现(Microsoft.VisualStudio.WebHost.Server
),因为你需要得到System.Web.HttpRuntime.Close()
调用发生在 Cassini 创建的用于托管 ASP.Net 的应用程序域内。
作为参考,这里是我使用嵌入式网络托管进行的工作单元测试的一些部分。
My WebServerHost
类是一个非常小的类,允许将请求编组到由System.Web.Hosting.ApplicationHost.CreateApplicationHost()
.
using System;
using System.IO;
using System.Web;
using System.Web.Hosting;
public class WebServerHost :
MarshalByRefObject
{
public void
Close()
{
HttpRuntime.Close();
}
public void
ProcessRequest(WebServerContext context)
{
HttpRuntime.ProcessRequest(new WebServerRequest(context));
}
}
The WebServerContext
类只是一个包装器System.Net.HttpListenerContext
派生自 System.MarshalByRefObject 的实例,以允许来自新 ASP.Net 托管域的调用回调到我的域。
using System;
using System.Net;
public class WebServerContext :
MarshalByRefObject
{
public
WebServerContext(HttpListenerContext context)
{
this.context = context;
}
// public methods and properties that forward to HttpListenerContext omitted
private HttpListenerContext
context;
}
The WebServerRequest
类只是抽象的实现System.Web.HttpWorkerRequest
通过 ASP.Net 托管域回调到我的域的类WebServerContext
class.
using System;
using System.IO;
using System.Web;
class WebServerRequest :
HttpWorkerRequest
{
public
WebServerRequest(WebServerContext context)
{
this.context = context;
}
// implementation of HttpWorkerRequest methods omitted; they all just call
// methods and properties on context
private WebServerContext
context;
}
The WebServer
class 是用于启动和停止 Web 服务器的控制器。启动后,ASP.Net 托管域是使用我的创建的WebServerHost
类作为代理以允许交互。 ASystem.Net.HttpListener
实例也会启动,并启动一个单独的线程来接受连接。建立连接后,线程池中会启动一个工作线程来处理请求,再次通过我的WebServerHost
班级。最后,当Web服务器停止时,监听器也停止,控制器等待接受连接的线程退出,然后关闭监听器。最后,HTTP 运行时也通过调用来关闭WebServerHost.Close()
method.
using System;
using System.IO;
using System.Net;
using System.Reflection;
using System.Threading;
using System.Web.Hosting;
class WebServer
{
public static void
Start()
{
lock ( typeof(WebServer) )
{
// do not start more than once
if ( listener != null )
return;
// create web server host in new AppDomain
host =
(WebServerHost)ApplicationHost.CreateApplicationHost
(
typeof(WebServerHost),
"/",
Path.GetTempPath()
);
// start up the HTTP listener
listener = new HttpListener();
listener.Prefixes.Add("http://*:8182/");
listener.Start();
acceptConnectionsThread = new Thread(acceptConnections);
acceptConnectionsThread.Start();
}
}
public static void
Stop()
{
lock ( typeof(WebServer) )
{
if ( listener == null )
return;
// stop listening; will cause HttpListenerException in thread blocked on GetContext()
listener.Stop();
// wait connection acceptance thread to exit
acceptConnectionsThread.Join();
acceptConnectionsThread = null;
// close listener
listener.Close();
listener = null;
// close host
host.Close();
host = null;
}
}
private static WebServerHost
host = null;
private static HttpListener
listener = null;
private static Thread
acceptConnectionsThread;
private static void
acceptConnections(object state)
{
while ( listener.IsListening )
{
try
{
HttpListenerContext context = listener.GetContext();
ThreadPool.QueueUserWorkItem(handleConnection, context);
}
catch ( HttpListenerException e )
{
// this exception is ignored; it will be thrown when web server is stopped and at that time
// listening will be set to false which will end the loop and the thread
}
}
}
private static void
handleConnection(object state)
{
host.ProcessRequest(new WebServerContext((HttpListenerContext)state));
}
}
最后,这个Initialization
类,用 NUnit [SetupFixture] 属性标记,用于在单元测试开始时启动 Web 服务器,并在单元测试完成时关闭它。
using System;
using NUnit.Framework;
[SetUpFixture]
public class Initialization
{
[SetUp]
public void
Setup()
{
// start the local web server
WebServer.Start();
}
[TearDown]
public void
TearDown()
{
// stop the local web server
WebServer.Stop();
}
}
我知道这并不能完全回答问题,但我希望这些信息对您有用。