0

I'm in dll hell.

I'm building a plugin for a huge, ancient and very powerful software suite called ANSYS. They have a plugin framework. I had hoped that they would magically handle everything for me via AssemblyContexts or AppDomains or some other clever dotnet device that I don't understand. They do not.

The result is that I've created an application that depends on GRPC.core 1.16.0 via nuget. I wrote a little application that drives my plugin with a winform host. It loads and works perfectly, finding my library in ~/myproject/bin/debug/grpc.core.1.1.16.dll that exists right beside the class-library that is my plugin, no problem.

When I run my plugin in the ANSYS process space, which happens to also depend on grpc 1.0.0.0, the linker finds C:\Program FIles\ANSYS\...\WIN64\grpc.core.dll. No Good.

One odd thing about the Nuget GRPC package is that it adds a reference with a "reference version" of 1.0.0.0, where most other nuget packages have their reference version match the nuget package version. If i manually change the reference version the compiler wont find the library.

<Reference Include="Grpc.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=d754f35622e28bad">
  <HintPath>..\packages\Grpc.Core.1.16.1\lib\net45\Grpc.Core.dll</HintPath>
</Reference>

edit: the key is in the above line. The Nuget published Grpc.core artifact is at AssemblyInformationVersion=1.16.1.0, AssemblyFileVersion=1.16.1.0, AssemblyVersion=1.0.0.0. I logged this as a request against GRPC. More Below.

Thus I need to tell the runtime linking facilities not to use grpc.core...dll found in ANSYS's own binary directoryWhats more, there is exactly one dll (and its dependents) that I wish to load from my parent processes context: and that's ANSYS API dlls themselves, which are probably already in the GAC. In my project I've included this as a non-nuget reference with "build action: do not copy" selected.

So my questions:

  1. is there something simple and easy I can do at runtime to tell the runtime-linker "when somebody loads a type from an assembly you think should be grpc.core, do not load 1.0.0.0, find 1.16.0.0 exactly"?

    the runtime was already matching the needed library by "strong name". The problem is that the 1.16.0 is a misnomer. That version string was informational, but the assembly itself was version 1.0.0.0. Fusion was loading the library I wanted by exact match already.

  2. is there something smarter I can do with appdomains or contexts or another C# device to explictly enter some kind of nested scope? Could I go so far as to log this as a bug in ANSYS's API?

I've tried digging into this myself, but I'm not a dotnet expert and finding out whether I'm looking at a nuget package configuration option --which isn't relevant to me, or an old-fashioned dotnet runtime option, has been very tricky.


update 1:

I've tried using AppDomain.CreateDomain, and it does indeed solve my problem, but it also requires me to provide a marshalling strategy for the already-loaded API objects. In other words, if you're programming against a plugin framework that has an api similar to:

public void DoMyPluginsFunctionality(ApiProvidedInputContext context){

  var myPlugin = AppDomain.Create(
      strongName: "MyCompany.MyPlugin.; Version=1.2.3.4 ...",
      baseDirectory: "C:\\Program Files\\MyPlugin\\bin"
  )
  //success! MyCompany.MyPlugin loads the version of GRPC I want!

  myPlugin.unWrapAsDynamicProxy().doFunctionality(context)
  //error: No marshalling strategy and/or not serializable and/or swizzling errors
}

Then the runtime will require you to marshall (serialize) the context variable, because .net will not let you share memory across AppDomain boundaries.

So my new question: - given I cant use AppDomains myself - given that Grpc.core is always published as AssemblyVersion=1.0.0.0

What are my options?

  • Stop using newer features of GRPC.core and live in fear of my parent processes dependencies
  • use a strategy similar to shading. Is there something like shading in the .net world?
  • Edit the published binary's version metadata. Can I dynamically edit a published binaries version?
  • rebuild GRPC myself with the version string updated --effectively a private fork of GRPC.

update 2:

The GRPC build system seems like its quite large and well maintained, so I'm hoping I can simply build it and change a vcproj file to include an updated version string.

Unfortunately it also seems quite complex, and I haven't quite got the targeting/cross-compiling (x64 targeting x86) worked out.

Groostav
  • 3,170
  • 1
  • 23
  • 27
  • This may help: [Assembly binding redirect: How and why?](https://stackoverflow.com/questions/43365736/assembly-binding-redirect-how-and-why) – John Wu May 11 '19 at 01:47
  • binding redirect won't help when the two files have the same assembly version. @Groostav what error do you actually get, you only said "no good". I just want to validate my assumption. – zivkan May 11 '19 at 08:52
  • I get a `TypeLoadException: Could not load type ... grpc.Interceptor`, which was added [here](https://github.com/grpc/grpc/pull/12613). Version redirection is all I'm looking for, though I suppose there is still wiggle-room if a use a library that doesn't use sane version-numbers. Is there no better solution to strictly enforce that I get exactly the DLLs I built with? – Groostav May 13 '19 at 17:30
  • and I'm sorry for being so obtuse @JohnWu, but doesn't the `app.config` file only apply to the `exe` project type? The way we deploy our plugin is as a class library with some magic method names that are "discovered" by the plugin system. – Groostav May 13 '19 at 17:37
  • Usually you'd configure the binding redirect for the entire application. This is what I would recommend. But it is also possible to create [.NET configuration for DLL files](https://www.sep.com/sep-blog/2010/09/05/configuration-settings-for-net-class-libraries-dlls/). – John Wu May 13 '19 at 19:06
  • In hindsite the problem is that all versions of GRPC have an `AssemblyVersion` of 1.0.0.0, _though they have different `AssemblyFileVersion` and `AssemblyInformationalVersion` attributes_, used by things like NuGet, to suggest different versions. Fusion is not able to pickup on this. I've created [this issue with GRPC](https://github.com/grpc/grpc/issues/19024) – Groostav May 14 '19 at 18:46

0 Answers0