Closed skovsende closed 7 years ago
This is not an issue with Moq, but a general dependency management issue that can arise when working with NuGet, so I will close this issue. Hopefully, though, one of the following three suggestions will help you:
I'd advise you not to update Castle.Core
just for the sake of updating. Perhaps there is no need for you to provoke a version conflict in the first place? That is, if you don't actually need 4.1.1 (e.g. because you're making use of Castle.Core directly), then let Moq 4.7.63 have its Castle.Core 4.1.0. This is the easiest option.
Try adding the required assembly version redirects to App.config
or Web.config
. (Sometimes, NuGet does this automatically for you.) See https://docs.microsoft.com/en-us/dotnet/framework/configure-apps/redirect-assembly-versions.
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Castle.Core" publicKeyToken="407dd0808d44fbdc" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.1.1.0" newVersion="4.1.1.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
Wait another few days, then update Moq to the next version; I'll be pushing a Moq update to NuGet in the next few days which will use Castle.Core 4.1.1 (see d96684e16b166a70f37225efb8fa7bde960649b7).
But would it not be more correct for moq to depend on a specific version of Castle.Core, by setting the dependency as:
<dependency id="Castle.Core" version="[4.1.0]" />
I am just asking out of curiosity here, so feel free to ignore me :)
No, in my opinion, that would not be more correct. (It would be correct if Moq were not a library, but an application; see links below.)
Pinning Moq to a very specific version of Castle.Core would be "correct" if you understand the version specification as a guarantee that Moq has been written against, and tested with, this exact version. The trouble here is that pinning only allows us to give one such guarantee, at the cost of making it much more likely that consumers will experience version conflicts like the one you've reported above. We want to avoid this if possible.
One way to avoid pinning is semantic versioning (semver), which most package managers these days use (including NuGet). Moq 4.7.63 declares that it requires Castle Core with any version 4.1.0 ≤ x < 5. This is more flexible than pinning one specific version, but it should still be valid because an increase in the minor version basically means more features (which Moq wouldn't know nor care about), but a new minor version may not introduce any breaking changes (which would affect Moq). Only an increase of the major version could introduce a breaking change (which is why we want to exclude version 5). Therefore, if Castle.Core follows semver rules correctly, we should have a guarantee that Moq can work with e.g. Castle Core 4.999.99 even though we've never explicitly tested it.
See also this question on Stack Overflow along with its answers, but especially this one. The question may be about Python, but the same principle is valid for other semver-compliant package management systems.
Yeah, I get the SemVer thing(but thanks alot for the references, they will come in handy! :)) - but just to make 100% sure that I have understand the problem. I only get the error I reported because Moq is signed, right? If it had been unsigned there would have been no problems changing the underlying dependency?
Thanks a bunch for taking the time to reply!
One aspect playing into this problem could be if you installed Moq and Castle.Core in a class library project. If you create a console app, install Castle.Core 4.1.1 and Moq 4.7.63, you'll see that NuGet automatically creates an assembly version redirect in App.config
, and things just work. That obviously cannot happen in a class library, which doesn't have its own App.config
file. (See also this Stack Overflow question, which claims that some test runners support a .dll.config
file.)
I only get the error I reported because Moq is signed, right?
To be honest, I haven't considered this aspect, but yes, the fact that Moq's assembly is signed strong-named might indeed influence assembly resolution and provoke version conflicts when minor versions don't match. I can't remember the exact rules, but will check up on this.
A possibility could be to have a Moq-unsigned version I suppose. But it looks like I'm the only one with the problem, so hardly worth doing.
But again, thanks a bunch for the patience, that was one bit of world class open source support.
OK, I performed a quick test. If you have an App.config
in your test project, and it contains the required assembly version redirect for Castle.Core, at least Visual Studio 2017's Test Explorer will apply that configuration. So if you add an App.config
to your test project with the assembly redirect (as shown above; NuGet should've added that automatically), there shouldn't be any problem.
I don't think an unsigned version of Moq is necessary.
Thanks a bunch for the patience, that was one bit of world class open source support.
You're welcome. And thank you for the kind feedback, that is much appreciated!
Well, in my case the updating of the reference is automated, I have a build that does a nuget update on the solution, tries to compile with the new set of libraries, and if it works, tests pass etc., commit the result. In that case the automation story gets a little more complicated if we need to mess about with updating app.config as well. So not worth it in this case - it's easy enough to just lock the dependency in place for now.
I wondered, because I have other "root" assemblies that have updated automaticly this way for some time, without problems. So I looked into it a bit.
My application uses Serilog with the Serilog.Sinks.Seq sink, both are seperate nuget packages, and the Serilog package have had multiple patch updates without us running into the problem I had with Moq.
But when I look at the Serilog package I see that even though the package itself is at 2.5, the assembly version is frozen at 2.0.0.0 - so it doesn't follow the package or file-version. So even though the Serilog.Sinks.Seq package depends on Serilog>=2.3.0 in the nuspec, the reference always points to 2.0.0.0, which means that my build doesn't break when Serilog has an update.
So in this case it would be equivalent to Caste.Core fixing their assembly version to 4.0.0.0.
I have no idea if this is a standard way of doing this - it seems kind of hackish by the Serilog guys.
@skovsende: That's very intriguing. There definitely seems to be a gap between (a) how .NET assembly versioning was designed (with things like the GAC etc.) and (b) the way NuGet manages package versions. I'm not sure what the current best practices are to bridge that gap, but I intend to find out.
If you do find out the best practices around the issue we just discussed, and how to avoid such version conflicts, and you see that Moq isn't following that best practice, then please open an issue so we can discuss this further and take the required actions!
Will do.
P.S.: https://codingforsmarties.wordpress.com/2016/01/21/how-to-version-assemblies-destined-for-nuget/ is the perfect summary for the discussion we've just had, and indeed the recommended solution is to pin the assembly version / specify only a major version.
It would be nice to know how common that practice is.
Yes, I found the same and was about to post it. It describes our exact problem!
@stakx If you use paket.exe it installs the highest version that satisfies the constraints, nuget.exe install the minimal version. Paket does the right thing here. The result is that if you add Moq you need to add a binding redirect if the it is not in sync with latest Castle version. Not that adding a redirect is hard but writing xml is not awesome either. Neither paket.exe nor nuget.exe adds redirects to dll projects AFAIR.
It would be correct if Moq were not a library, but an application; see links below.
Not sure I follow here, pinning makes a lot of sense as redirects are needed unless the matching version of Castle is installed.
Neither paket.exe nor nuget.exe adds redirects to dll projects AFAIR.
Possibly. FWIW, Visual Studio 2017 does (I checked earlier today) at least sometimes.
Not sure I follow here [...]
I would recommend you take a look at the Stack Overflow answer I linked to above, it does an excellent job of explaining this. The gist is that applications are at the top of the dependency graph and can have full control over all dependencies; libraries are not in the same fortunate situation and thus shouldn't force consumers to use any specific version.
If you use paket.exe
I've heard good things about Paket, but I am not the one to decide which package manager people use. That being said, thanks for sharing that bit of knowledge; perhaps switching to Paket can help some people avoid some conflicts! :)
@skovsende - For what it's worth, I've just pushed a new NuGet version of Moq (4.7.99) that uses Castle.Core 4.1.1, in case you want to upgrade and remove any assembly redirects you've had to set up.
Works like a charm. Cheers.
I'm having this issue with 4.2.1 where specifying the version or leaving it off don't work, but the following made it happy:
<dependentAssembly>
<assemblyIdentity name="Castle.Core" publicKeyToken="407dd0808d44fbdc" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.99999.99999.99999" newVersion="4.0.0.0" />
</dependentAssembly>
Guys can this please be fixed? Currently if I attempt to add Moq through nuget manager in Visual Studio, it will always fail at runtime saying it was looking for Castle.Core at version 4.0.0.0, no redirects work. I've spent 4 hours trying to get it to work, it's just plain broken.
Did anyone get Moq to work through nuget?
This has been fixed to the extent that it can be fixed. Assembly versioning is difficult because .NET and NuGet use different versioning schemes, tooling is broken, and most people simply don't understand the intricacies of it all. Even Microsoft admits this is a pain point. See also #461 and dotnet/coreclr#14263.
Simple fix: upgrade Moq to the latest version (same for Castle Core if you're managing it explicitly, which you probably shouldn't unless your code makes direct use of it), and remove all binding redirects from your config file for these two libraries.
Using Moq 4.7.63, when upgrading Castle.Core to 4.1.1, the following code throws an exception:
The exception is this:
It's an NUnit test, not that I can see that matteing, and it fails in the first line of my SetUp. It fails both in my Resharper test runner and on my build server which uses the NUnit commandline runner. What confuses me is that if I create a simple console program with the following it runs fine:
A quick google search doesn't turn up anything sensible, so I'm inclined to think I'm missing something obvious.
Any ideas would be appreciated.