Mamy duże rozwiązanie .NET z projektami C# i C++/CLI, które się do siebie nawzajem odwołują. Mamy również kilka projektów testowania jednostek. Niedawno uaktualniliśmy Visual Studio 2010 z wersji & .NET 4.0 do Visual Studio 4.5 & .NET 4.5, a teraz, gdy próbujemy uruchomić testy jednostkowe, wydaje się, że wystąpił problem podczas ładowania niektórych bibliotek DLL podczas testu.DLLs załadowane z niewłaściwej AppplicationBase podczas próby załadowania bibliotek dll C# i C++/CLI w nowej AppDomain
Problem pojawia się, ponieważ testowanie jednostki odbywa się w oddzielnym AppDomain. Proces testowania jednostkowego (na przykład nunit-agent.exe) tworzy nową AppDomain z AppBase ustawioną na lokalizację projektu testowego, ale według dziennika Fusion niektóre biblioteki DLL są załadowane katalogiem wykonywalnym nunit jako AppBase zamiast AppBomain AppBase .
Udało mi się odtworzyć problem za pomocą prostszego scenariusza, który tworzy nową AppDomain i próbuje uruchomić tam test. Oto jak to wygląda (I zmienił nazwy klas testowych jednostki, metod i lokalizacji dll, aby chronić niewinnych):
class Program
{
static void Main(string[] args)
{
var setup = new AppDomainSetup {
ApplicationBase = "C:\\DirectoryOfMyUnitTestDll\\"
};
AppDomain domain = AppDomain.CreateDomain("MyDomain", null, setup);
ObjectHandle handle = Activator.CreateInstanceFrom(domain, typeof(TestRunner).Assembly.CodeBase, typeof(TestRunner).FullName);
TestRunner runner = (TestRunner)handle.Unwrap();
runner.Run();
AppDomain.Unload(domain);
}
}
public class TestRunner : MarshalByRefObject
{
public void Run()
{
try
{
HtmlTransformerUnitTest test = new HtmlTransformerUnitTest();
test.SetUp();
test.Transform_HttpEquiv_Refresh_Timeout();
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
}
Jest to wyjątek uzyskać, gdy próbuje wykonać test urządzenia. Jak widać, problem dzieje dll C++ jest inicjowany i próbuje załadować biblioteki dll C# (zmieniłem nazwy DLL zaangażowanych do CPlusPlusDll i CSharpDll):
System.TypeInitializationException: The type initializer for '' threw an exception. ---> .ModuleLoadExceptionHandlerException: A nested exception occurred after the primary exception that caused the C++ module to fail to load. ---> System.TypeInitializationException: The type initializer for '' threw an exception. ---> .ModuleLoadException: The C++ module failed to load during vtable initialization. ---> System.IO.FileNotFoundException: Could not load file or assembly 'CSharpDll, Version=8.80.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified. at [email protected]@[email protected]@[email protected]@@YMXXZ() at _initterm_m((fnptr)* pfbegin, (fnptr)* pfend) in f:\dd\vctools\crt_bld\self_x86\crt\src\puremsilcode.cpp:line 219 at .LanguageSupport.InitializeVtables(LanguageSupport*) in f:\dd\vctools\crt_bld\self_x86\crt\src\mstartup.cpp:line 331 at .LanguageSupport._Initialize(LanguageSupport*) in f:\dd\vctools\crt_bld\self_x86\crt\src\mstartup.cpp:line 491 at .LanguageSupport.Initialize(LanguageSupport*) in f:\dd\vctools\crt_bld\self_x86\crt\src\mstartup.cpp:line 702 --- End of inner exception stack trace --- at .ThrowModuleLoadException(String errorMessage, Exception innerException) in f:\dd\vctools\crt_bld\self_x86\crt\src\minternal.h:line 194 at .LanguageSupport.Initialize(LanguageSupport*) in f:\dd\vctools\crt_bld\self_x86\crt\src\mstartup.cpp:line 712 at .cctor() in f:\dd\vctools\crt_bld\self_x86\crt\src\mstartup.cpp:line 754 --- End of inner exception stack trace --- at System.Runtime.InteropServices.Marshal.ThrowExceptionForHRInternal(Int32 errorCode, IntPtr errorInfo) at System.Runtime.InteropServices.Marshal.ThrowExceptionForHR(Int32 errorCode) at .DoCallBackInDefaultDomain(IntPtr function, Void* cookie) in f:\dd\vctools\crt_bld\self_x86\crt\src\minternal.h:line 406 at .DefaultDomain.Initialize() in f:\dd\vctools\crt_bld\self_x86\crt\src\mstartup.cpp:line 277 at .LanguageSupport.InitializeDefaultAppDomain(LanguageSupport*) in f:\dd\vctools\crt_bld\self_x86\crt\src\mstartup.cpp:line 342 at .LanguageSupport._Initialize(LanguageSupport*) in f:\dd\vctools\crt_bld\self_x86\crt\src\mstartup.cpp:line 539 at .LanguageSupport.Initialize(LanguageSupport*) in f:\dd\vctools\crt_bld\self_x86\crt\src\mstartup.cpp:line 702 --- End of inner exception stack trace --- at .ThrowNestedModuleLoadException(Exception innerException, Exception nestedException) in f:\dd\vctools\crt_bld\self_x86\crt\src\minternal.h:line 184 at .LanguageSupport.Cleanup(LanguageSupport* , Exception innerException) in f:\dd\vctools\crt_bld\self_x86\crt\src\mstartup.cpp:line 662 at .LanguageSupport.Initialize(LanguageSupport*) in f:\dd\vctools\crt_bld\self_x86\crt\src\mstartup.cpp:line 710 at .cctor() in f:\dd\vctools\crt_bld\self_x86\crt\src\mstartup.cpp:line 754 --- End of inner exception stack trace ---
to co widzę w Fusion Log (zmieniłem nazwę pliku DLL do SomeDLL.dll zamiast oryginału):
*** Assembly Binder Log Entry (8/1/2013 @ 01:47:48 PM) *** The operation failed. Bind result: hr = 0x80070002. The system cannot find the file specified. Assembly manager loaded from: C:\Windows\Microsoft.NET\Framework\v4.0.30319\clr.dll Running under executable c:\users\yshany\documents\visual studio 2012\Projects\MyTester\MyTester\bin\Debug\MyTester.exe --- A detailed error log follows. === Pre-bind state information === LOG: User = WF-IL\yshany LOG: DisplayName = SomeDLL, Version=8.80.0.0, Culture=neutral, PublicKeyToken=null (Fully-specified) LOG: Appbase = file:///c:/users/yshany/documents/visual studio 2012/Projects/MyTester/MyTester/bin/Debug/ LOG: Initial PrivatePath = NULL LOG: Dynamic Base = NULL LOG: Cache Base = NULL LOG: AppName = MyTester.exe Calling assembly : (Unknown). === LOG: This bind starts in default load context. LOG: Using application configuration file: c:\users\yshany\documents\visual studio 2012\Projects\MyTester\MyTester\bin\Debug\MyTester.exe.Config LOG: Using host configuration file: LOG: Using machine configuration file from C:\Windows\Microsoft.NET\Framework\v4.0.30319\config\machine.config. LOG: Policy not being applied to reference at this time (private, custom, partial, or location-based assembly bind). LOG: Attempting download of new URL file:///c:/users/yshany/documents/visual studio 2012/Projects/MyTester/MyTester/bin/Debug/SomeDLL.DLL. LOG: Attempting download of new URL file:///c:/users/yshany/documents/visual studio 2012/Projects/MyTester/MyTester/bin/Debug/SomeDLL/SomeDLL.DLL. LOG: Attempting download of new URL file:///c:/users/yshany/documents/visual studio 2012/Projects/MyTester/MyTester/bin/Debug/SomeDLL.EXE. LOG: Attempting download of new URL file:///c:/users/yshany/documents/visual studio 2012/Projects/MyTester/MyTester/bin/Debug/SomeDLL/SomeDLL.EXE. LOG: All probing URLs attempted and failed.
Jak widać, problem jest taki, że AppBase gdzie MyTester.exe rezyduje, zamiast gdzie znajduje się plik SomeDLL.dll (który jest tą samą lokalizacją, co dll testowy jednostki). Dzieje się tak w przypadku kilku bibliotek DLL, w tym obu bibliotek DLL wymienionych w powyższym wyjątku.
Próbowałem również odtworzyć za pomocą prostszego projektu testu jednostkowego (małe rozwiązanie VS2012 z 3 projektami - projekt C# odwołujący się do projektu C++/CLI, który odwołuje się do innego projektu C#), ale problem nie powtarzał się i zadziałało perfekcja. Jak wspomniałem wcześniej, testy jednostkowe były w porządku, zanim zaktualizowaliśmy do VS2012 & .NET 4.5.
Co mogę zrobić? Dzięki!
zdarza się tylko z nunit-TestRunner? Czy możesz również zaimportować go za pomocą MSTest? –
Zdarza się w NUnit, MSTest, a także w programie Tester, który tutaj napisałem. –
Ta obfuskacja nie pomaga nam. Jaki jest związek między "CSharpDll" i "SomeDLL"? –