So I have some users getting this error

System.MissingMethodException: Method not found: 'Void System.Net.Http.Headers.HttpHeaders.AddWithoutValidation(System.String, System.Collections.Generic.IEnumerable`1<System.String>)'.
   at System.Net.Http.HttpHeaderExtensions.CopyTo(HttpContentHeaders fromHeaders, HttpContentHeaders toHeaders)
   at System.Net.Http.ObjectContent..ctor(Type type, HttpContent content)
   at System.Net.Http.HttpContentExtensions.ReadAsAsync[T](HttpContent content)
   at Octgn.Site.Api.ApiClient.Login(String username, String password)

I cannot reproduce this locally, but some people using my WPF app end up having this error. After some digging through the logs I see this

LOADED ASSEMBLY: System.Net.Http, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Net.Http\v4.0_2.0.0.0__b03f5f7f11d50a3a\System.Net.Http.dll

I've tried in the csproj changing this

<Reference Include="System.Net.Http, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
  <HintPath>..\..\packages\Microsoft.Net.Http.2.0.20710.0\lib\net40\System.Net.Http.dll</HintPath>
</Reference>

to this

<Reference Include="System.Net.Http">
  <HintPath>..\..\packages\Microsoft.Net.Http.2.0.20710.0\lib\net40\System.Net.Http.dll</HintPath>
</Reference>

I've also tried adding this to the app.config file

    <dependentAssembly>
        <assemblyIdentity name="System.Net.Http" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
        <bindingRedirect oldVersion="1.0.0.0 - 4.0.0.0" newVersion="2.0.0.0"/>
    </dependentAssembly>

None of these things seem to want to load the dll's that are in the same directory as the exe of my project. I have the dll's locally and I can't seem to get it to avoid the GAC. This is a product so it goes out to hundreds of people a day, so I'm hoping to find some solution that doesn't require the user to manually be doing something on their machine at the end.

I've also though about preemptively loading the dll in code on load with Assembly.Load or something similar, but I'm not sure if that would even make a difference, and I would think there would be a more elegant solution.

Ok, so what about if I merged all of those new assemblies into a new assembly using ilmerge http://www.microsoft.com/en-us/download/details.aspx?id=17630 ? Or does the GAC use namespaces etc? Well I'm trying it...when I get the people with the problem to test it I'll report back if it worked or not.

Any ideas?

有帮助吗?

解决方案 4

I used ilmerge, and merged the assemblies into my library and got around it.

其他提示

If you are referencing an assembly which is strongly named and that assembly is in the GAC (with the same strong name, i.e. version number and public key token) then the .Net framework will always load that assembly from the GAC, unless that assembly has already been loaded.

If you have copy of that DLL that you want to load instead then that DLL needs to have a different strong name (or not be strongly named) so that the .Net framework can tell that the one in the GAC is different and that it should look somewhere else (e.g. alongside your application) - from the sounds of things this is going to involve modifying your local copy of that DLL somehow, e.g. remove the strong name.

Once the two dlls have different strong names (or the local one is not strongly named) using binding redirects should work correctly.

Update: Alternatively you can try explicitly loading the local copy of that assembly (e.g. using Assembly.Load) before the .Net framework loads that assembly, in which case the .Net framework might use the already loaded one instead of looking in the GAC. (untested)

FYI, I can't find the method System.Net.Http.Headers.HttpHeaders.AddWithoutValidation(...) in my machine. I do, however, see System.Net.Http.Headers.HttpHeaders.TryAddWithoutValidation(...).

To me it seems that you have a non-RTM version of the DLL (System.Net.Http.dll) with the old method signature. Since most users don't have this installed, .NET will use the local copy and all is well.

The users who is having issues may have installed the RTM version (presumably bundled with a different software package). In this case, .NET will use the GAC version since it is more recent.

I stand by my suggestion in the comments, clean up your dev and build machines from non-RTM libraries, recompile, and redeploy.

You can not avoid loading assembly from the GAC (*) if CLR decides that good enough match is present in the GAC. No amount of local copies will help you.

(*) you can try can not even use LoadFrom using bytes: Understanding The CLR Binder

In the case of assemblies loaded into the LoadFrom context, the Binder first checks to see if the exact assembly (same identity and location) is already present in the Load context. If it is, it discards the assembly information in the LoadFrom context and uses the assembly information from the Load context.

More information on assembly loading can be found by searching for Suzanne Cook's blogs and related references.

Note: in this particular case solution is likely to detect this rogue non-RTM binary in the GAC (i.e. by attempting to make that exact call and checking for "missing method" exception) and show message with resolution steps instead of trying to circumvent normal Load policy.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top