2

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?

Kelly Elton
  • 4,373
  • 10
  • 53
  • 97
  • 2
    Based on http://stackoverflow.com/questions/10862728/asp-net-web-api-error-after-upgrading-to-visual-studio-2012-rc-method-not-found, it seems that you're using a method that is no longer available. The proper way of fixing it would be to use the RTM version of the library, recompile, and deploy. – Adrian Godong Jul 03 '13 at 02:20
  • I've seen this before when the user had an old version of .Net installed; .Net 2.0 can run code compiled against .Net 3.5 (since the runtime is the same), but .Net 3.5 introduced new methods and classes, and you see the error you get here. I would go with the Assembly.Load big-hammer approach to get things working again, so you can comfortably figure this out the right way. – antiduh Jul 03 '13 at 02:20
  • I should mention it works fine on .net 4.0, and systems with .net 4.5, just some systems happen to have those files in their GAC for whatever reason. From what I've seen it doesn't come with a fresh .net install. – Kelly Elton Jul 03 '13 at 02:53
  • @AdrianGodong Rtm version? That was the first stack overflow question I checked. This software works on most machines, it's just a small amount for some reason have these files in their GAC. These are standard users on the net, most have no knowledge of development or web development. I imagine some software vendor decided to drop them in there for whatever reason. – Kelly Elton Jul 03 '13 at 02:55

4 Answers4

3

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)

Justin
  • 84,773
  • 49
  • 224
  • 367
  • +1 - good suggestion on making new strong name if possible (also it not helpful for actual problem OP has). Note: you should not be able to load local copy if GAC one exists, apparently even `LoadFrom` - see article I've just linked in my answer. – Alexei Levenkov Jul 03 '13 at 19:39
1

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.

Alexei Levenkov
  • 98,904
  • 14
  • 127
  • 179
  • 1
    AFAIK, there is no way to circumvent the GAC. The assembly identity is checked even when loaded from raw bytes and it will be loaded from the GAC if it has a strong name and there is a match. – Mike Zboray Jul 03 '13 at 05:11
  • @mikez - you are right, thanks. I thought that using LoadFrom may work, but indeed it should not - I've updated answer with link to the article. – Alexei Levenkov Jul 03 '13 at 19:35
1

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.

Adrian Godong
  • 8,802
  • 8
  • 40
  • 62
  • This software works on most machines, it's just a small amount for some reason have these files in their GAC. These are standard users on the net, most have no knowledge of development or web development. I imagine some software vendor decided to drop them in there for whatever reason. I am deploying the correct version. – Kelly Elton Jul 03 '13 at 21:24
  • The version I'm using is the latest stable WebApi Client Libraries, updated the 16th of may I believe it says https://www.nuget.org/packages/Microsoft.AspNet.WebApi.Client/4.0.30506.0 – Kelly Elton Jul 04 '13 at 17:37
  • I think you're looking at the wrong place. The WebApi Client Libraries are fine, the issue seems to lie on the .NET Framework itself. Take a look at the latest documentation for System.Net.Http.Headers.HttpHeaders class http://msdn.microsoft.com/en-US/library/system.net.http.headers.httpheaders.aspx. The AddWithoutValidation() method is no longer documented. If you're still seeing it in your development machine, your .NET Framework may be outdated. – Adrian Godong Jul 08 '13 at 21:13
  • Both clients had the same version of 4.5 installed. – Kelly Elton Jul 08 '13 at 21:48
1

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

Kelly Elton
  • 4,373
  • 10
  • 53
  • 97