2009-02-18 71 views
9

我正在使用Cassini/WebServer.WebDev運行一些使用NUnit的WebService的自動化測試。Cassini/WebServer.WebDev,NUnit和AppDomainUnloadedException

我沒有做什麼特別的,只是

public class WebService{ 
    Microsoft.VisualStudio.WebHost.Server _server; 

    public void Start(){ 
    _server = new Microsoft.VisualStudio.WebHost.Server(_port, "/", _physicalPath); 
    } 

    public void Dispose() 
    { 
    if (_server != null) 
    { 
     _server.Stop(); 
     _server = null; 
    } 
    } 
} 
[TestFixture] 
public void TestFixture{ 
    [Test] 
    public void Test(){ 
    using(WebService webService = new WebService()){ 
     webService.Start(); 
     // actual test invoking the webservice 
    } 
    } 
} 

,但是當我運行使用NUnit-console.exe它,我得到以下的輸出:

NUnit version 2.5.0.9015 (Beta-2) 
Copyright (C) 2002-2008 Charlie Poole.\r\nCopyright (C) 2002-2004 James W. Newki 
rk, Michael C. Two, Alexei A. Vorontsov.\r\nCopyright (C) 2000-2002 Philip Craig 
.\r\nAll Rights Reserved. 

Runtime Environment - 
    OS Version: Microsoft Windows NT 6.0.6001 Service Pack 1 
    CLR Version: 2.0.50727.1434 (Net 2.0.50727.1434) 

ProcessModel: Default DomainUsage: Default 
Execution Runtime: net-2.0.50727.1434 
..... 
Tests run: 5, Errors: 0, Failures: 0, Inconclusive: 0 Time: 28,4538451 seconds 
    Not run: 0, Invalid: 0, Ignored: 0, Skipped: 0 


Unhandled exceptions: 
1) TestCase1 : System.AppDomainUnloadedException: Attempted to access an unloaded AppDomain. 
2) TestCase2 : System.AppDomainUnloadedException: Attempted to access an unloaded AppDomain. 
3) TestCase3 : System.AppDomainUnloadedException: Attempted to access an unloaded AppDomain. 
4) TestCase4 : System.AppDomainUnloadedException: Attempted to access an unloaded AppDomain. 

如果我跑nunit-在調試器下的控制檯,我得到下面的輸出在調試控制檯:

[...] 
The thread 0x1974 has exited with code 0 (0x0). 
############################################################################ 
##############     S U C C E S S    ################# 
############################################################################ 
Executed tests  : 5 
Ignored tests  : 0 
Failed tests   : 0 
Unhandled exceptions : 4 
Total time   : 25,7092944 seconds 
############################################################################ 
The thread 0x1bd4 has exited with code 0 (0x0). 
The thread 0x10f8 has exited with code 0 (0x0). 
The thread '<No Name>' (0x1a80) has exited with code 0 (0x0). 
A first chance exception of type 'System.AppDomainUnloadedException' occurred in System.Web.dll 
##### Unhandled Exception while running 
System.AppDomainUnloadedException: Attempted to access an unloaded AppDomain. 
    at System.Web.Hosting.ApplicationManager.HostingEnvironmentShutdownComplete(String appId, IApplicationHost appHost) 
    at System.Web.Hosting.HostingEnvironment.OnAppDomainUnload(Object unusedObject, EventArgs unusedEventArgs) 
A first chance exception of type 'System.Threading.ThreadAbortException' occurred in mscorlib.dll 
A first chance exception of type 'System.Threading.ThreadAbortException' occurred in mscorlib.dll 
A first chance exception of type 'System.Threading.ThreadAbortException' occurred in System.Web.dll 
The thread 0x111c has exited with code 0 (0x0). 
The program '[0x1A64] nunit-console.exe: Managed' has exited with code -100 (0xffffff9c). 

做任何人有任何想法什麼可以b引起這個?

+0

你有沒有找到解決這個問題的辦法?我有類似的問題。 – 2009-11-12 12:19:31

+0

不是一個/好/解決方案,但我最終在NUnit任務上設置了failonerror =「false」,並用一個單獨的工具後處理xml-output,忽略了未處理的AppDomainUnloadedException。 – 2009-11-12 15:01:32

回答

7

我有同樣的問題,但沒有使用卡西尼。相反,我有我自己的網絡服務器託管基於System.Net.HttpListener與ASP.Net支持通過System.Web.HttpRuntime運行在不同的應用程序域通過System.Web.Hosting.ApplicationHost.CreateApplicationHost()創建。這基本上是卡西尼的工作方式,除了卡西尼工作在套接字層並且實現了由System.Net.HttpListener本身提供的許多功能。

無論如何,爲了解決我的問題,在讓NUnit卸載我的應用程序域之前,我需要調用System.Web.HttpRuntime.Close()。我在我的主機代理類中公開了一個新的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()調用卡西尼創建以託管ASP.Net應用領域內發生。

作爲參考,這裏是我的工作單位測試與嵌入式虛擬主機的一些片斷。

我的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)); 
    } 
} 

WebServerContext類只是圍繞着從System.MarshalByRefObject派生,以允許新的ASP.Net宿主域調用回調到我的域System.Net.HttpListenerContext實例的包裝。

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; 
} 

WebServerRequest類就是抽象System.Web.HttpWorkerRequest類回調到經由WebServerContext類的ASP.Net託管域我域的實現。

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; 
} 

WebServer類是用於啓動和停止Web服務器的控制器。啓動時,ASP.Net託管域將與我的WebServerHost類一起作爲允許交互的代理來創建。一個System.Net.HttpListener實例也會啓動並啓動一個單獨的線程來接受連接。在建立連接時,線程池中將啓動一個工作線程來處理請求,同樣通過我的WebServerHost類。最後,當Web服務器停止時,監聽器停止,控制器等待線程接受連接退出,然後關閉監聽器。 最後,HTTP運行時也通過調用WebServerHost.Close()方法關閉。

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(); 
    } 
} 

我知道這不是完全回答這個問題,但我希望你能找到有用的信息。