xUnit Tests from VS Test Explorer fail to find runtime.dll's

2045
8
09-27-2021 08:48 AM
qsmgruber
New Contributor II

Hello,

when calling ArcGIS code from unit tests, I receive the following exception: "System.InvalidOperationException : Invalid ArcGISRuntime deployment folder, missing folder arcgisruntime100.9\client64". 

Here are the steps I took / things I already found out to narrow down the problem:

  • Tested with arcgisruntime 100.9 and 100.12 on .NET Framework 4.8
  • Only happens when running the tests from the visual studio built-in test explorer (Resharper test explorer works fine)
  • Only happens with xUnit framework (nUnit works fine)
  • Only happens when the test project is built for x64 (which we need to do, haven't tried for x86, but AnyCPU works)

The deployment folder mentioned in the error message is the exact folder where runtimecore.dll etc. are copied to when platform is set to AnyCPU. I guess this is why the AnyCPU configuration works.

For x64, the .dlls are located directly in bin\x64\Debug, but the test runner seems to expect them to be in bin\x64\Debug\arcgisruntime100.9\client64.

I set the option "Processor Architecture for AnyCPU Projects" available in the VS test explorer settings to x64, but that did not help.

My guess is that the xUnit specific VS test runner is somehow still configured as AnyCPU, but I could not find any info on how to change that. 

Steps to reproduce: 

  1. Create a test project with the nuget packages Esri.ArcGISRuntime.WPF, xunit and xunit.runner.visualstudio.
  2. Set solution platform to x64.
  3. Run this test: 

 

       [Fact]
        public void SomeTest()
        {
            ArcGISTiledLayer currentMapLayer = new ArcGISTiledLayer(new Uri("https://tiledbasemaps.arcgis.com/arcgis/rest/services/World_Imagery/MapServer")) { NoDataTileBehavior = NoDataTileBehavior.UpSample };
        }​

 

I know that this might be more a xunit related issue, but I was hoping you could still investigate.

Thanks

0 Kudos
8 Replies
dotMorten_esri
Esri Notable Contributor

The issue is likely that the manage runtime can't find its native libraries if they aren't deployed in the same folder as your executable (which is likely the test runner and not your test library). You can try setting the InstallPath property on test startup to help it find it if you're using .NET Framework (If you one day move to use .NET Core / .NET 5, there's a different way to hint the runtime where native libs are to be loaded from)

0 Kudos
qsmgruber
New Contributor II

Thanks for the quick reply. 

Adding the InstallPath as follows did not change anything.

[Fact]
public void SomeTest(){
    ArcGISRuntimeEnvironment.InstallPath = Environment.CurrentDirectory;
    // Environment.CurrentDirectory = ...\bin\x64\Debug
    ArcGISTiledLayer currentMapLayer = new ArcGISTiledLayer(new Uri("https://tiledbasemaps.arcgis.com/arcgis/rest/services/World_Imagery/MapServer")) { NoDataTileBehavior = NoDataTileBehavior.UpSample };
}

 What would be the way to do it in .NET 5?

0 Kudos
dotMorten_esri
Esri Notable Contributor

 

ArcGISRuntimeEnvironment.InstallPath = Environment.CurrentDirectory;

 

The path should be to where the arcgisruntime100.x folder is, not current directory (we already search current).

With .NET Core 3.1 and .NET 5+ you'd instead use the DllImportResolvers to help hinting at where libraries are located. However this might not be necessary, as these targets uses a built-in way to get the runtimes deployed that .NET Framework doesn't have, so things "might just work". Example: 

 

              System.Runtime.InteropServices.NativeLibrary.SetDllImportResolver(typeof(Esri.ArcGISRuntime.ArcGISRuntimeEnvironment).Assembly, new System.Runtime.InteropServices.DllImportResolver(DllImportResolver));
  
// ...

 private static IntPtr runtimeLibPtr = IntPtr.Zero;

private static IntPtr DllImportResolver(string libraryName, Assembly assembly, System.Runtime.InteropServices.DllImportSearchPath? searchPath)
        {
            if (libraryName == "RuntimeCoreNet.dll")
            {
                if (runtimeLibPtr == IntPtr.Zero)
                {
                    System.Runtime.InteropServices.NativeLibrary.TryLoad(@$"installpath\client{(Environment.Is64BitProcess ? "64" : "32")}\RuntimeCoreNet.dll", out runtimeLibPtr);
                }
                return runtimeLibPtr;
            }
            return IntPtr.Zero;
        }

 

 

0 Kudos
qsmgruber
New Contributor II

When I call "Environment.CurrentDirectory", it returns the path to the build output directory, which is where the arcgisruntime100.x folder is located. So e.g. ...\bin\x64\debug.

0 Kudos
qsmgruber
New Contributor II

As a workaround, I mirrored the expected folder structure in the source folder and added the missing runtime dlls manually. So in the test project, I created a folder ...\arcgisruntime100.9\client64, added runtimecore.dll, runtimecorenet.dll and runtimecorenet.wpf.dll, and set the build action to Content -> Copy If Newer for those dlls.

dotMorten_esri
Esri Notable Contributor

Any chance you could share a small simple xunit sample project that uses the runtime and demonstrates the problem? I'd like to see if we can't make this a bit easier, or work with the xunit team if something here is missing.

0 Kudos
qsmgruber
New Contributor II

I created this sample project. It demonstrates how the xUnit test fails while the nUnit test does not with the same configuration. Note that the project configuration needs to be manually set from AnyCPU to x64 in visual studio.

0 Kudos
dotMorten_esri
Esri Notable Contributor

Thank you! Much appreciated. I'm able to reproduce the issue and will log a bug for this. I think I might know what the problem is. Hopefully we can address this for the next release.

dotMorten_esri_0-1633123513093.png

 

0 Kudos