devlooped / moq

The most popular and friendly mocking framework for .NET
Other
5.94k stars 802 forks source link

MissingMethodException / "Method not found" after update to Moq 4.8.0 #566

Closed JHotterbeekxBannerconnect closed 6 years ago

JHotterbeekxBannerconnect commented 6 years ago

Hi,

Today I've tried updating the NuGet package from 4.7.145.0 to 4.8.0.0 and I'm running into an issue with a specific test case failing now on a strange error message. To give you some context, in our tests we create a HttpActionContext to test our authentication. This is native .net functionality. I've isolated the issue to the following code:

[Test]
public void OnActionExecuting_ShouldFillMarketInSession() {
  var fakeActionContext = _CreateFakeHttpActionContext();
}

private HttpActionContext _CreateFakeHttpActionContext() {
  return new HttpActionContext(null, new ReflectedHttpActionDescriptor()) {
    Response = new HttpResponseMessage(HttpStatusCode.OK)
  };
}

When running this test, it fails with the following error:

System.MissingMethodException : Method not found: 'Void System.Web.Http.Controllers.HttpActionContext.set_Response(System.Net.Http.HttpResponseMessage)'. at SMP.Api.Test.Filter.MoqTest._CreateFakeHttpActionContext() at SMP.Api.Test.Filter.MoqTest.OnActionExecuting_ShouldFillMarketInSession() in C:\Projects\Athena\Athena\SMP.Api.Test\Filter\MoqTest.cs:line 14

Could you help me figure out what is wrong, or fix this if it is an actual bug?

Thanks, John

stakx commented 6 years ago

Hi @JHotterbeekxBannerconnect and thanks for reporting. Unfortunately, I do not see anything related to Moq in your example code, so I have to wonder whether your issue is even related to Moq at all.

Could you please provide a short but complete code example that demonstrates this issue, and shows how Moq is involved? (Otherwise I'll close this issue in a couple of days' time.) Thank you!

(Btw. MissingMethodExceptions usually indicate that you have old DLLs lurking around somewhere that are not binary-compatible with the version against which your code was compiled. Try deleting your project's obj and bin folders, your test runner's cache (if applicable), and possibly also your project's or user profile's NuGet package cache.)

willykc commented 6 years ago

Hi, I think I'm seeing the same problem. Out of 405 tests using Moq, 16 started failing after upgrading to Moq 4.8.0 with exception "System.MissingMethodException: Method not found". It seems to be related to the "System.Net.Http" namespace since all the "missing methods" in the failing tests have types from that namespace in their signature (eg. "System.Net.Http.HttpResponseMessage").

stakx commented 6 years ago

@JHotterbeekxBannerconnect, @willykc: Could it be that you updated not just Moq, but any other Microsoft ASP.NET packages at the same time without noticing it? Because quite frankly, Moq has no dependency on, nor any special logic related to, any System.Net.Http.* types. I don't see how this issue could be caused by Moq, especially when the MissingMethodException gets triggered in a piece of code that doesn't even involve Moq.

JHotterbeekxBannerconnect commented 6 years ago

We've updated several packages, but saw tests failing. So I reverted everything and updated one by one, everything keeps working until the last package is updated, which is Moq. But I'm going to try cleaning old DLL's and cache and see what that does, and if it still doesn't work try a new solution to reproduce this.

stakx commented 6 years ago

@JHotterbeekxBannerconnect: That's truly strange. Until you have repro code ready to share, could you perhaps give the following information:

JHotterbeekxBannerconnect commented 6 years ago

@stakx I've been able to reproduce it in a simple test project: Working.without.Moq.zip

When you open this (in VS 2017) you'll see that there is one single test in there. This runs without any issues. Now try adding through NuGet, you'll see that the test fails.

I've found something more interesting, when updating to the latest version of Moq through NuGet, another package seems to come along called System.Threading.Tasks.Extensions.4.4.0. This is the one that seems to be causing the error, because if I remove this as reference from the included test project, the test will succeed again.

The other info you requested (for the test solution):

Hopefully this is enough for you to reproduce it.

stakx commented 6 years ago

Thanks a lot for the test solution, and the analysis you've done already! I can now reproduce this issue.

(One problem I noticed before I could even run your tests is that your project is a missing System.Web.Http assembly. I've resolved this one by installing the Microsoft.AspNet.WebApi.Core package.)

I'll now try to find the precise cause of this.

stakx commented 6 years ago

OK, seems you're affected by the problem described in https://github.com/dotnet/standard/issues/481, and adding the following to your MoqTests.csproj file appears to resolve the issue:

<PropertyGroup>
  <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
  <GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>
</PropertyGroup>

(PS: Alternatively, update your project file(s) to the new SDK format, which should already implicitly include the above properties.)

The problem indeed gets triggered by System.Threading.Tasks.Extensions package (which Moq references because of ValueTask<TResult>). Note that it does not target the full .NET Framework, only .NET Standard. Referencing a .NET Standard assembly from a .NET Framework project used to not work, but support for doing just that was added in .NET 4.6.1. Unfortunately, it's a pretty flaky feature and it sometimes requires assembly binding redirects (which your test project doesn't have).

Please see the issue referenced above for details.

JHotterbeekxBannerconnect commented 6 years ago

@stakx Thanks a lot for the help and explanation! I've added the properties to the solution and the tests run without any issue now. Seems like something that more people could run into, maybe this should be put in the wiki somewhere?

stakx commented 6 years ago

@JHotterbeekxBannerconnect - I agree that this situation needs to be improved. I'm currently looking into Moq's reference of the System.Threading.Tasks.Extensions package (which was added in 2194e5fe). It doesn't seem right that this package is referenced at all by the net45 target, as this framework version didn't yet allow references to .NET Standard assemblies. And then there's that issue I linked to to deal with.

Adding a warning to the wiki would be a start... would you like to do this?

Short of temporarily removing ValueTask<TResult> support in Moq for the full .NET Framework, I'm not sure how to cleanly resolve this problem. @AdamDotNet — you added the package reference to System.Threading.Tasks.Extensions to Moq a while ago. Do you by chance know how to properly deal with this kind of problem (cross-target assembly references)?

I'm also still not sure yet why just referencing that assembly caused the issue (note that your test doesn't make use of it).

JHotterbeekxBannerconnect commented 6 years ago

@stakx I've added it as a FAQ to the wiki, referencing to the .net standard issue and this issue. Great that you'll look in to this, I agree that it feels weird that this issue is being caused, and even stranger without actually using anything from the reference.

willykc commented 6 years ago

Hi @stakx, thanks a lot for the solution. After adding the property group to my test project file, all the failing tests are now passing.

I'm not sure if this could help but an idea would be to add a .props file including the property group to the Moq NuGet package like so: https://docs.microsoft.com/en-us/nuget/create-packages/creating-a-package#including-msbuild-props-and-targets-in-a-package

JHotterbeekxBannerconnect commented 6 years ago

@stakx It seems that the adding of a .net standard reference was also causing issues on our TeamCity servers, which we had to resolve as well by updating the build tools and adding .net Core support. Just telling you because this could become an issue for more people.

stakx commented 6 years ago

@JHotterbeekxBannerconnect, thanks a lot for setting up the FAQ! It's great to have such a resource that we can direct people to. :+1:

@willykc, that's good to know—thanks for the link. However, I don't feel too comfortable about Moq influencing the build process behind the user's back. Moq is just a library and just one out of many possible dependencies a project might have. Imagine the potential complications if every dependency secretly modified your build. Some people might not actually want to have assembly binding redirects generated automatically.

I believe the problem should be solved at the source, if possible. And I suspect it's that the build process picks the wrong assembly version from the System.Threading.Tasks.Extensions package (starting with .NET 4.6.1, it can pick either the .NET Standard assembly, or the Portable Class Library assembly, the latter of which is probably the right one to pick). I'll try to figure out the exact circumstances under which this problem appears.

If all else fails, I'm quite ready to temporarily remove ValueTask<TResult> support from Moq so people don't run into this while we find a permanent solution.

I'll keep you updated!

AdamDotNet commented 6 years ago

@stakx My understanding is that, it's not .Net 4.6.1 that enabled referencing .Net Standard libraries, it's that .Net 4.6.1 was the lowest version that works with .Net Standard 2.0 specifically. The tooling (VS) helps you reference .Net Standard libraries, not necessarily the Framework you are targeting.

The System.Threading.Tasks.Extensions NuGet has a dependency on .Net Standard 1.0, the lowest common denominator. Microsoft's documentation on .Net Standard states that a 1.0 library is compatible with .Net Framework 4.5. Therefore, it shouldn't be a problem to have the net45 TFM reference the System.Threading.Tasks.Extensions NuGet. Visual Studio / NuGet.exe should pick up the "most correct" version of the NuGet when multiple targets are available.

However, it is possible to only reference the NuGet on a specific TFM, and then #if out the relevant code if that's what you want. In fact, the Moq CSProj already does that.

For what it's worth, I just tried the following sample code on a .Net 4.5 console app without any compilation, or runtime issues; using VS 2017 15.5.2.

using Moq;
using System;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    public interface IFoo
    {
        ValueTask<string> Bar();
    }

    class Program
    {
        static async Task Main(string[] args)
        {
            Mock<IFoo> mock = new Mock<IFoo>();
            mock.Setup(m => m.Bar()).ReturnsAsync("Hello world");

            string bar = await mock.Object.Bar();
            Console.WriteLine(bar);
        }
    }
}

Does this answer your questions?

PS. I definitely have felt the pain of .Net Standard in .Net Framework :(

stakx commented 6 years ago

Let me summarize my findings regarding MissingMethodExceptions in Moq 4.8.0. Below, you'll find:

  1. a very minimal test project which reproduces the issue;
  2. an explanation of what exactly triggers it; and
  3. a description of how to resolve this issue.

(I originally wanted to include a rant about .NET Core, .NET Standard, and NuGet having put us back firmly in DLL hell, and about the continually sorry state of .NET tooling surrounding those three; but anyone working with .NET who hasn't lived under a rock in the past few years probably knows that already, so I've edited it out. 😜)

1. Test project that reproduces a MissingMethodException:

Download it here: MinimalRepro.zip (1.4 KB).

minimalrepro

Please note:

2. Why is the MissingMethodException occurring?

My personal conclusion is that System.Net.Http or some of the ASP.NET assemblies are versioned incorrectly. https://github.com/aspnet/Hosting/issues/926#issuecomment-276674380 hints at the same thing ("...some of the ongoing issues with the System.Net.Http packages...").

3. How can I resolve this problem?

As mentioned above, try adding this to your .csproj or .vbproj project file:

<PropertyGroup>
  <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
  <GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>
</PropertyGroup>

(This shouldn't be necessary if you're using the new SDK project file format, so you can also just convert to that instead.)

stakx commented 6 years ago

And finally... 🥁

4. What can be done at Moq's end?

  1. What I would like to do first is... nothing, for these reasons:

    • I'd like to see how many people actually run into this problem.
    • I'd like to see whether this problem occurs mostly within the context of ASP.NET. This would indicate that the ASP.NET folks version their assemblies incorrectly. If, however, the problem happens in a lot of different scenarios, then the tooling would be to blame.
  2. l'll direct the first few people at the FAQ set up by @JHotterbeekxBannerconnect.

  3. Beyond that, if more complaints keep rolling in, I might remove support for ValueTask<> and ValueTuple<> from Moq's net45 target. It's pretty much the only possible fix until enough time has passed for people to upgrade their tools and projects to a working combination of NuGet / MSBuild / VS.

I am open to suggestions how to resolve this in a better way.

AdamDotNet commented 6 years ago

@stakx - I think for now your suggestion of wait and see a little longer probably best. The "holy grail" of .Net Standard sounded really cool until it all fell apart in actual use (in .Net Framework). System.Net.Http is probably the biggest offender, as you've found out. I can't find the war story that came to mind, but it was bad...

A possible solution is to create a Moq.Extensions NuGet. Then treats like ValueTask can be opt in rather than everyone just gets it.

stakx commented 6 years ago

@AdamDotNet, thanks for this feedback, it's much appreciated. Wait a little longer it is, then!

A possible solution is to create a Moq.Extensions NuGet. Then treats like ValueTask can be opt in rather than everyone just gets it.

This is a pretty good idea! We just might do that if things don't get better soon. Thank you for suggesting it! (And, if you'd like to contribute by moving the offending bits into a separate package via a PR, please just let me know. I could signal you when the time's right.)

AdamDotNet commented 6 years ago

@stakx - I could probably find time to create a new project in the Moq solution and move things over (a list of exactly what you want moved over would be appreciated, if more than just ValueTask). I'm not familiar with how you configure the build server script though.

stakx commented 6 years ago

@AdamDotNet - Thanks for the kind offer. If it turns out that we actually need to do this in order to resolve the issue in a clean fashion, I'd be happy to guide you. Adding another project and .nupkg to the build script should be fairly straightforward. kzu might have to set up a new API key on NuGet, not sure about that. Let's wait a bit longer and worry about the details if and when we actually get that far... agreed?

stakx commented 6 years ago

@AdamDotNet: It has belatedly occurred to me that moving all ValueTask<> and ValueTuple<> related functionality to a separate assembly / package isn't actually feasible. This would work for extension methods, such as this one:

https://github.com/moq/moq4/blob/cf10cdb0f220eb3551a8dc451ac94a6f0dc06439/Source/ReturnsExtensions.cs#L35-L38

but it wouldn't work in other cases such as here:

https://github.com/moq/moq4/blob/cf10cdb0f220eb3551a8dc451ac94a6f0dc06439/Source/LookupOrFallbackDefaultValueProvider.cs#L79-L93

without creating a module initializer (global static constructor) which C# does not support, so I fear an extension NuGet package is no way out of DLL hell. :-/

tothdavid commented 6 years ago

Hi,

We are also affected by this issue.

So I would like to have a short question: As I can see System.Threading.Tasks.Extension 4.3.0 version package does have net45 target. Could it be a short-term solution to downgrade to 4.3.0 as a dependency to Moq? Probably it would solve this issue as .net core assemblies would not be copied to the build target so the version clash would not happen. I tried cloning the repo and downgrading the package and it seems like after a successful build all the tests pass. Obviously I am not familiar with the Moq solution and tooling so there may be some issue that I can't see.

Thanks, David

stakx commented 6 years ago

Hi @tothdavid. Hopefully the fix mentioned above works for you. Regarding your questions:

As I can see System.Threading.Tasks.Extension 4.3.0 version package does have net45 target.

Yes, but I am not sure this is going to help. 4.4.0 also targets the .NET Framework 4.5, via the Portable Class Library TFM. But the build targets will obviously not pick that one, but favour one of the .NET Standard TFMs instead.

Could it be a short-term solution to downgrade to 4.3.0 as a dependency to Moq?

I suspect that wouldn't help, because 4.3.0 also targets .NET Standard 1.0, and like I wrote above I suspect that the build targets will favour that one over the more specific .NET 4.5 TFM.

It might be worth a try, even though it means that everyone who has .NET Core 2.0 build tools installed will then likely get upgrade warnings.

Thank you for suggesting this, regardless of whether it'll work or not.

I tried cloning the repo and downgrading the package and it seems like after a successful build all the tests pass. Obviously I am not familiar with the Moq solution and tooling so there may be some issue that I can't see.

Moq's own test suite already passes, or Moq wouldn't have been published at all. :wink: The question is whether your projects' tests will pass if you use a custom-built version of Moq that targets STTE 4.3.0 instead of 4.4.0... is this what you tried? (If you run Moq's build.cmd on a developer command line prompt, you should end up with a .nupkg inside the out\ folder. You can then install that to some NuGet source using nuget add -Source <path> -Expand <path to .nupkg>, then restore your test project's NuGet packages from that source.)

At the end of the day, this is really Microsoft's problem to solve. Moq's choices are all about equally bad and limited. As far as I can see, it boils down to two questions:

  1. Should Moq have support for ValueTask<> and ValueTuple<>? That question is largely rhethorical as it's been answered already by past feature requests and PRs.
  2. Would it be OK to temporarily remove that support for the net45 TFM?
AdamDotNet commented 6 years ago

@stakx - Maybe this is over-engineering it a bit, but we could make a "plugin" system in order to do a module load.

  1. Moq looks for IMockModule in the bin folder - could be slower because it would check all of the user's dlls too. But can be considered a user extension point. Could be configurable and is off by default.
  2. Moq looks for "known" extension dlls only, should be faster.

With either choice, Moq does not fail to start if no IMockModules are found. The IMockModule has the methods needed to bootstrap like you showed with LookupOrFallbackDefaultValueProvider.cs.

The cons are fairly bad though, in my opinion: start up time slowed down, complicated code, etc.

stakx commented 6 years ago

@AdamDotNet - The biggest con in my opinion is the fact that a plugin system (which per se isn't a bad idea at all!) wouldn't be needed under normal circumstances. If we add a plugin system now, just to circumvent a .NET tooling issue, we'll have to maintain it, even afterwards. We'd also have to point out, each time another build-related problem is reported, that the plugin system is there to circumvent this-and-that, and explain exactly how, which is another kind of work that we shouldn't have to bear in the first place. I'd say let's not rush things, even though the current situation is hugely unsatisfactory.

<edit> removed rant about the currently sorry state of .NET tooling </edit>

stakx commented 6 years ago

@tothdavid - you might just have saved everyone's day! 👏

I have tried what you suggested and downgraded System.Threading.Tasks.Extensions to 4.3.0. Other people's mileage may vary, but on my developer machine and with a simply repro project, this results in NuGet picking the .NET Framework-specific assembly over the .NET Standard one, meaning MSBuild won't copy dozens of .NET Standard shim DLLs to the output directory, which in turn means less assembly version conflicts. I'll look into this some more, then release an updated version of Moq.

tothdavid commented 6 years ago

@stakx thanks, you are great. I will upgrade to the new version tomorrow. Actually I did try earlier to install STTE 4.3.0 package instead of 4.4.0 following your example which did not include Moq as a dependency at all and it worked here as well.

stakx commented 6 years ago

Just published Moq version 4.8.1 on NuGet (changelog) which depends on an earlier release of System.Threading.Tasks.Extensions as suggested by @tothdavid.

Everyone, could you please test whether 4.8.1 fixes the problem? In order to test properly, you should temporarily disable the fix that you might have applied earlier. (That is, either remove the <AutoGenerateBindingRedirects> etc. from your project file, or set the property to false.)

(You will find that Moq 4.8.1 additionally depends on System.ValueTuple. This might seem counterproductive. However, if we want Moq to eventually have ValueTuple<> support, we'll have to add this dependency sooner or later, and I'd rather get it over with now than having to encounter the same issue again in a few weeks.)

tothdavid commented 6 years ago

@stakx I can confirm, the new version fixes the issue (at least for me). The ValueTuple dependency also did not introduce any similar problem.

JHotterbeekxBannerconnect commented 6 years ago

@stakx It seems to work in the test project that I created, however I am having troubles getting it to work in our main project. When removing Moq, with dependencies and afterwards installing version 4.8.1, I can see that System.Threading.Tasks.Extensions and System.ValueTuple are now 4.3.0. However trying to run any test now results in the following error:

System.TypeInitializationException : The type initializer for 'Moq.DefaultValueProvider' threw an exception.
  ----> System.IO.FileLoadException : Could not load file or assembly 'System.Threading.Tasks.Extensions, Version=4.1.1.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)

And I haven't been able to figure out the cause for this error.

stakx commented 6 years ago

@JHotterbeekxBannerconnect, I suppose you've already made sure that you're working with a clean output directory. Can you provide a small test code for the problem you're seeing now?

JHotterbeekxBannerconnect commented 6 years ago

@stakx Yes, everything has been cleaned before running the tests. I'll going to try and find some room in the next days to reproduce this on a smaller scale.

stakx commented 6 years ago

Posted by @clottman in https://github.com/moq/moq4/issues/567#issuecomment-356641367:

I'm having a similar issue on Moq 4.8.1, explicitly that System.Threading.Tasks.Extensions cannot be found. It was working before we updated from a lower version (pre 4.8.0).

System.TypeInitializationException: The type initializer for 'Moq.DefaultValueProvider' threw an exception. ---> System.IO.FileLoadException: Could not load file or assembly 'System.Threading.Tasks.Extensions, Version=4.1.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040).

Downgrading back to 4.7.145 resolves the issue for me.

rikrak commented 6 years ago

@stakx V4.8.1 appears to resolve similar issues (related to System.Net.Runtime) we were experiencing after updating to v4.8.0. One thing to note with regards to my situation: we were building all projects to a single folder in the root of the solution folder.

rikrak commented 6 years ago

@JHotterbeekxBannerconnect Not sure if this is relevant to your situation, but I had to clear out and amend a load of assembly redirects from the test project's app.config after installing v4.8.1 of Moq. Essentially I had a rogue redirect:

      <dependentAssembly>
        <assemblyIdentity name="System.Threading.Tasks.Extensions" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-4.1.1.0" newVersion="4.1.1.0" />
      </dependentAssembly>

Which should be:

     <dependentAssembly>
        <assemblyIdentity name="System.Threading.Tasks.Extensions" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-4.1.0.0" newVersion="4.1.0.0" />
      </dependentAssembly>

The difference being in the version numbers

JHotterbeekxBannerconnect commented 6 years ago

@rikrak Thanks for the hint! @stakx I've got it working in solution as well. It did take some work, but eventually I just removed Moq, and it's dependencies. Cleared the line which @rikrak pointed out and installed the latest version of Moq, now everything works fine. Thanks for all the trouble!

stakx commented 6 years ago

It appears that everyone in this thread who has reported having this issue now got things working, with the exception of @clottman, who hasn't yet responded. I'd like to close this issue for now. If the problem surfaces again, or we get more repro code here, I'm happy to reopen.

robinbihun commented 6 years ago

I'm receiving the same error with Moq nuget package 4.8.1 in a .net 4.6.2 test project.

Was able to work around it by modifying the .csproj file and changing the reference path from the netstandard2.0 folder to the net462 folder for SystemValue Tuple and from the netstandard1.0 to portable-net45+win8+wp8+wpa81 for System.Threading.Tasks.Extensions.

    <Reference Include="System.Threading.Tasks.Extensions, Version=4.1.1.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
      <HintPath>..\packages\System.Threading.Tasks.Extensions.4.4.0\lib\portable-net45+win8+wp8+wpa81\System.Threading.Tasks.Extensions.dll</HintPath>
    </Reference>
    <Reference Include="System.ValueTuple, Version=4.0.2.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
      <HintPath>..\packages\System.ValueTuple.4.4.0\lib\net461\System.ValueTuple.dll</HintPath>
    </Reference>
stakx commented 6 years ago

@robbihun: The problem likely is no longer Moq but your using versions 4.4.0 of these two System packages. Try downgrading them to 4.3.0.

rhyous commented 6 years ago

Did anyone submit a bug with System.Threading.Tasks.Extensions.4.4.0 to get a fix for this issue? Or is there a workaround for this breaking change?

Update: This workaround to manually edit the csproj to use the portalable library in the NuGet package worked for me.

    <Reference Include="System.Threading.Tasks.Extensions, Version=4.1.1.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
      <HintPath>..\..\packages\System.Threading.Tasks.Extensions.4.4.0\lib\portable-net45+win8+wp8+wpa81\System.Threading.Tasks.Extensions.dll</HintPath>
    </Reference>
stakx commented 6 years ago

Did anyone submit a bug with System.Threading.Tasks.Extensions.4.4.0 to get a fix for this issue?

If any one particular package is versioned incorrectly, it would likely be System.Net.Http. But the real problem isn't with any one specific package, IMHO, but the fact that .NET 4.6.1 has been changed retroactively to support and prefer .NET Standard 2.0 over portable libraries, thereby resulting in conflicts between framework DLLs and differently-versioned .NET Standard shim DLLs being copied over to your project's output directory.

Or is there a workaround for this breaking change?

See above: https://github.com/moq/moq4/issues/566#issuecomment-355222021.

This workaround to manually edit the csproj to use the portalable library in the NuGet package worked for me.

Glad you found a solution that works for you. But your manual changes will probably be overwritten next time you upgrade packages.

rhyous commented 6 years ago

If any one particular package is versioned incorrectly, it would likely be System.Net.Http.

I didn't think System.Net.Http was even a package involved, as it is not an installed NuGet package. However, taking into account .NET Standard shim DLLs, this makes sense. The System.Net.Http objects could be seen as completely different object in the shims.

Glad you found a solution that works for you. But your manual changes will probably be overwritten next time you upgrade packages.

Exactly why I want to follow this up. I would love for my manual changes to be overwritten AND the bug to be fixed and not notice this when the next version comes out.

stakx commented 6 years ago

Exactly why I want to follow this up.

I understand. Unfortunately, there's not much we can do here at the Moq project other than fixing #578.

I suggest you take this up directly with the .NET team. Like I said above, please see the issue I linked to in the comment above (https://github.com/dotnet/standard/issues/481). To be very honest with you, I am really quite fed up with (and burned out a little due to) the .NET assembly versioning mess that's been going on for the past few years, so please don't count on my support. :-/

I sincerely do hope, however, that if you follow up on this, that you'll be successful in getting this through to Microsoft.

ManfredLange commented 6 years ago

Further to this: I am receiving this problem with a project in new csproj format targeting net461. Although not required, I tried it with and without the workaround adding properties AutoGenerateBindingRedirects and GenerateBindingRedirectsOutputType. No success either way. Up to now we used Moq version 4.7.8 which worked. We are trying to upgrade to Moq version 4.8.2. This also upgrades Castle.Core from version 4.0.0 to version 4.2.1.

Since we have 50+ projects with test in them switching mocking frameworks would be an expensive/risky exercise which obviously we would like to avoid.

Anyone has any other suggestion for what we could try to resolve this issue?

Update: We were using Moq to mock HttpResponseBase which is an abstract base class and at times challenging to properly mock in the first place. We have implemented our own class HttpResponseBaseMock which derives from HttpResponseBase. While we would have preferred to continue using Moq for this, it seems to be outside of the limitations of what can be done. With our explicit mock implementation we have been able to work around the problem.

rhyous commented 6 years ago

Did you go back to System.Threading.Tasks.Extensions.4.3.0 and make sure it is using the dll from the portable-net45+win8+wp8+wpa81 folder?

Also, just FYI, I minimized the bug, taking Moq out of the picture. The bug I submitted on this to the dotnet project was added to Milestone 5. https://github.com/dotnet/corefx/issues/27907

ManfredLange commented 6 years ago

@rhyous Thank you for the suggestion. We found a work around. We were using Moq to mock HttpResponseBase, HttpRequestBase and HttpContextBase. We now have our own explicit mocks in place for these. We have almost 60 projects in our solution so going back and forth between different versions of 3rd party libraries has its limitations both technically and time wise. We appreciate that it seems to a be an issue within dotnet and unrelated to Moq. In our case it appeared when we upgraded Moq. We acknowledge that it's not caused by Moq.

We continue to use Moq for almost all our mocking needs, so please keep up the excellent work on this project. Thank you!

stakx commented 6 years ago

@ManfredLange - Thanks for the kind words. May I suggest that you watch #605 (or rather, look out for the future Moq version where this particular issue will be resolved) if you're still interested in seeing this resolved?

It's likely that due to that issue, we'll soon add .NET Standard 2.0 as a framework target to the Moq NuGet package. I haven't carved out an exact plan yet, but adding direct support for .NET Standard 2.0 will likely mean, among other things, less NuGet package dependencies. If we update Moq's dependency on System.Threading.Tasks.Extensions to package version 4.4.0, then Moq should no longer bring in the System.Net.Http package via System.Runtime into your projects. I'm not sure if it'll work out like that in your case (you might have to update the problematic unit test projects to .NET 4.7), but it's perhaps worth a try.

(Perhaps, if you still have enough patience left to deal with this at all :wink:, you could try the following already now: Upgrade the problematic unit test projects to .NET 4.7, and explicitly bring in the System.Threading.Tasks.Extensions package and pin that dependency at version 4.4.0. Afterward, bring in Moq 4.8.2. You might then need an assembly version redirect for STTE because Moq expects version 4.3.0.)

ManfredLange commented 6 years ago

@stakx We are migrating our projects across from net461 to netstandard2.0 / netcoreapp2.0 at the moment. For that process we believe that going to .NET 4.7, then to netstandard2.0 would be more of a sidetrack. We are happy to continue use Moq. We always knew that mocking HttpRequestBase, HttpResponseBase and HttpContextBase could be a stretch. And mocking of these classes will change with ASP.NET Core MVC again as far as we know.

We are definitely looking forward to netstandard2.0 support for Moq. :-)

willapp commented 6 years ago

I see this is a very long thread and apologies I didn't read every single post, but I have just been bitten with what appears to be the same issue upgrading from 4.7.145.0 to 4.8.0.0, although getting a different error when running some unit tests:

System.TypeInitializationException : The type initializer for 'Moq.DefaultValueProvider' threw an exception. ----> System.IO.FileNotFoundException : Could not load file or assembly 'System.Runtime, Version=4.0.10.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies. The system cannot find the file specified. ----> System.IO.FileNotFoundException : Could not load file or assembly 'System.Runtime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies. The system cannot find the file specified.

This is in a .Net Framework 4.5 assembly and is fixed by reverting back to 4.7.145.0 and removing the System.Threading.Tasks.Extensions nuget package so I can only assume it's related.

I know Moq is a community project but it would be nice if this breaking change had been made into a major version update so we could be a bit more confident that a minor release won't break our projects.