I have a C# class which calls a .Net assembly built from a Matlab function. I am able to call this function from a simple C# console application with no problems.
However if I try to run a unit test from NUnit I get the following exception:
ClassLibrary1.Tests.UnitTests.TestPerformOptimization: System.Reflection.TargetInvocationException : Exception has been thrown by the target of an invocation. ----> System.Exception : Error marshalling .NET object. 'Message: Unable to find assembly 'ClassLibrary1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'. Source: mscorlib HelpLink: '
I get the same error if I try to call the class from either the standalone NUnit console, from ReSharper's test runner or if I try to call the function from say Excel (using Excel-DNA).
When calling my compiled Matlab component I actually wrap up a C# method (in an MWObjectArray object) and inject it in. I think the problem is happening when the compiled Matlab component tries invoking this injected method.
The only workaround I've found is to simply place a copy of my class (containing the method that is injected) in the same location as the NUnit test runner, the ReSharper test runner or Excel. However this is simply not a practical solution going forward as I need to install this application onto users machines. The other option which I can't use is copying the files to my %DEVPATH% for the same reason.
Is there a way I can tell the Matlab component where to find the assembly of my injected method/class?
SAMPLE PROJECT DOWNLOAD
There is a sample project available for download here. Just follow the instructions in the README.txt file located in the zip file.
Update 1
I manage to get my unit test to recognise my assembly by modifying my class to include the following in its constructor:
AppDomain.CurrentDomain.AssemblyResolve +=
(sender, args) => typeof(OptimizationFunction).Assembly;
However now I get the following exception:
Exception: System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.Exception: Error marshalling .NET object. 'Message: Could not load file or assembly 'dotnetcli, Version=1.0.5488.33915, Culture=neutral, PublicKeyToken=da1231a838c93da4' or one of its dependencies. A strongly-named assembly is required. (Exception from HRESULT: 0x80131044) Source: mscorlib HelpLink: ' at dotnetcli.throwNetExceptionID(BaseMsgID* msgId) at dotnetcli.DeployedDataConversion.GetMxArrayFromObject(Object data)
--- End of inner exception stack trace --- at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)
So now it has a problem resolving the dotnetclli.dll (See Fusion log/exception below) which as far as I know should reside only in C:\Program Files (x86)\MATLAB\MATLAB Runtime\v85\bin\win32.
Here's an excerpt from the Fusion Log:
=== Pre-bind state information ===
LOG: DisplayName = ClassLibrary1 (Partial) WRN: Assembly Name: ClassLibrary1 | Domain ID: 1 WRN: A partial bind occurs when only part of the assembly display name is provided. WRN: This might result in the binder loading an incorrect assembly. WRN: It is recommended to provide a fully specified textual identity for the assembly, WRN: that consists of the simple name, version, culture, and public key token. > WRN: See whitepaper http://go.microsoft.com/fwlink/?LinkId=109270 for more information and common solutions to this issue. LOG: Appbase = file:///C:/XXXXX/ConsoleApplication1/packages/NUnit.Runners.2.6.3/tools/ LOG: Initial PrivatePath = NULL LOG: Dynamic Base = NULL LOG: Cache Base = NULL LOG: AppName = nunit-agent-x86.exe Calling assembly : (Unknown).
=== LOG: This bind starts in default load context. LOG: Using application configuration file: C:\Insight\TFS\Asg\ConsoleApplication4\packages\NUnit.Runners.2.6.3\tools\nunit-agent-x86.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:/XXXXX/ConsoleApplication4/packages/NUnit.Runners.2.6.3/tools/ClassLibrary1.DLL. LOG: Attempting download of new URL file:///C:/XXXXX/ConsoleApplication1/packages/NUnit.Runners.2.6.3/tools/ClassLibrary1/ClassLibrary1.DLL. LOG: Attempting download of new URL file:///C:/XXXXX/ConsoleApplication1/packages/NUnit.Runners.2.6.3/tools/lib/ClassLibrary1.DLL. LOG: Attempting download of new URL file:///C:/XXXXX/ConsoleApplication1/packages/NUnit.Runners.2.6.3/tools/lib/ClassLibrary1/ClassLibrary1.DLL. LOG: Attempting download of new URL file:///C:/XXXXX/ConsoleApplication1/packages/NUnit.Runners.2.6.3/tools/addins/ClassLibrary1.DLL. LOG: Attempting download of new URL file:///C:/XXXXX/ConsoleApplication1/packages/NUnit.Runners.2.6.3/tools/addins/ClassLibrary1/ClassLibrary1.DLL. LOG: Attempting download of new URL file:///C:/XXXXX/ConsoleApplication1/packages/NUnit.Runners.2.6.3/tools/ClassLibrary1.EXE. LOG: Attempting download of new URL file:///C:/XXXXX/ConsoleApplication1/packages/NUnit.Runners.2.6.3/tools/ClassLibrary1/ClassLibrary1.EXE. LOG: Attempting download of new URL file:///C:/XXXXX/ConsoleApplication1/packages/NUnit.Runners.2.6.3/tools/lib/ClassLibrary1.EXE. LOG: Attempting download of new URL file:///C:/XXXXX/ConsoleApplication1/packages/NUnit.Runners.2.6.3/tools/lib/ClassLibrary1/ClassLibrary1.EXE. LOG: Attempting download of new URL file:///C:/XXXXX/ConsoleApplication1/packages/NUnit.Runners.2.6.3/tools/addins/ClassLibrary1.EXE. LOG: Attempting download of new URL file:///C:/XXXXX/ConsoleApplication1/packages/NUnit.Runners.2.6.3/tools/addins/ClassLibrary1/ClassLibrary1.EXE. LOG: All probing URLs attempted and failed.
WRN: Partial binding information was supplied for an assembly: How come my console app can resolve this assembly by my NUnit test cannot?
Update 2
I got the following response from Matlab when I contacted them:
As far as I know this is the default .NET behavior when it comes to deserializations. The application which deserializes the class looks for the assembly in its own current folder and GAC where it cannot find it. It is similar to (when you read this replace MATLAB with Nunit)
You example does not represent the situation when MATLAB is involved. MATLAB sends the class across APPDomains. Your example does not do that.
Use Fuslogvw to have a look at the binding. You will see that it is not MATLAB which cannot find the assembly it’s the calling application which is unable to resolve the dependency (in your case nunit-agent-x86.exe).
Make sure all needed files are produced by the compilation of ConsoleApplication4 and placed besides the executable (e.g. any needed assembly DLL, runtime DLL, .config file, etc.)
Once you are sure this happens, start NUnit with the --no-shadow-copy command line switch, or set it as a configuration parameter from your GUI tool. As Bush said, NUnit usually copies the files under test to a separate directory, and may leave behind important files.
If the class created by Matlab needs some sort of specific runtime, make sure it is correctly installed in the computers where you are running the tests / using Excel/ReSharper.
I would not try to fiddle, at this level, with the Assembly resolution process: please sum up the content at the article you linked, because it's paywalled, and try with NUnit's no-shadow-copy setting.
A propos first problem:
It will log where your app looked for assemblies and how it failed. It probably means that working directory of nunit was different from working directory used by your console application.
A propos second error: strongly named assembly is required means that the library you have tried to use was not signed. If it's your assembly you simply have to use visual studio's sign the assembly from project properties. If it's not your assembly you can decompile it and compile it with strong name (with this method), but provider of third party dll should give you a strong-named assembly.
My guess this issue comes from an .NET CLR version incompatibility. Some client's (I mean client who calls your assembly) loads different versions of the CLE, then the resolved assembly may incompatible with that loaded CLR. This could cause not found error, because a compatible assembly really not found.
Try to check/play with both client's versions (the console app) and the server's version (your assembly) and diagnose what is changing.
Also check your assembly reference has "Copy to the output directory" is checked in all projects
You will want to study how the probing operation happens at .NET load time. Here's the rules for that: https://msdn.microsoft.com/en-us/library/yx7xezcf(v=vs.110).aspx
Outside of including the bin in the assembly you are publishing, it's the loader that decides if the support cast of DLLs are loadable. If it cannot find it using the rules above then you are simply out of luck.
We have seen issues similar to this in the past, some developer says to system admin, here's the Dlls you need to get the app running. System Admin follows instructions and boom, the application fails at load time.
Reason: Some child of a child in the assembly referred to a dll that's NOT on the system based on the probing rules.
Solution 1) Get the (child of the child) dll to include all dependencies in its assembly 2) Change the newer Main assembly to include all the dependencies (if the children assemblies cannot be changed). 3) Manually copy them in. 4) Create an installer that does it all.
Is the assembly in the Global Assembly Cache (GAC) or any place the might be overriding the assembly that you think is being loaded? This is usually the result of an incorrect assembly being loaded, for me it means I usually have something in the GAC overriding the version I have in bin/Debug.
My guess this issue comes from an .NET CLR version incompatibility. Some client's (I mean client who calls your assembly) loads different versions of the CLE, then the resolved assembly may incompatible with that loaded CLR. This could cause not found error, because a compatible assembly really not found.
Try to check/play with both client's versions (the console app) and the server's version (your assembly) and diagnose what is changing.
Also check your assembly reference has "Copy to the output directory" is checked in all projects
User contributions licensed under CC BY-SA 3.0