NLog version: 4.2.3, 4.3.5, 4.5.10, ...
Platform: .Net 3.5 / .Net 4.0 / .Net 4.5
We have a product that has a dependency on NLog v4.3.5.
A user of our product mentions that he receives the following error:
Method not found: 'Void NLog.Targets.FileTarget..ctor(System.String)
After investigation, we found out that the user had a version of NLog v4.2.3 installed in the GAC. (Probably a dependency of another application).
When NLog was removed from the GAC, our application ran without error.
Some further digging revealed that both versions of NLog (4.3.5 and 4.2.3) have the same assembly-version (4.0.0.0) although the public API of these versions is incompatible.
According to the Microsoft documentation, the AssemblyVersion is part of the Assembly-Identity.
When loading an assembly, the .NET runtime will first check if it can find the assembly in the GAC. In this case, a matching assembly was found (hence, NLog, Assembly version 4.0.0.0) and the assembly from the GAC is used.
I've verified the latest version of NLog that is available at the time of writing (4.5.10), and that version also has the same AssemblyVersion.
It seems to me that you should make sure that the AssemblyVersion is different amongst versions of NLog that are not compatible.
I think the simplest solution is to make sure that the AssemblyVersion of NLog matches the version of the product.
For example, the AssemblyVersion for NLog v4.3.5 should be 4.3.5.0 instead of 4.0.0.0. This will avoid these kind of problems.
Hi,
This is by design and a lot of OSS libraries do the same (e.g. JSON.NET).
If we change the assemblyversion every time, people get assembly load issues/difficulties.
For every major version, the assemblyversion will be the same and this works because we take semantic versioning (semver) very serious.
In you case it goes indeed wrong, and there are the following solution:
I think the simplest solution is to make sure that the AssemblyVersion of NLog matches the version of the product.
FYI: That's not simple as this will give many problems to other users because the assembly is strong named.
JSON.NET screenshot:

I don't understand what issues people might have when you make sure the assembly-version is changed for each new release ?
When you upgrade your project to a newer version of NLog, most people will do this via a nuget update. When rebuilding your project, the dependency will be written in the manifest with the correct versionnumber.
As for the solutions that you propose:
Use the same version as the one that's inside the GAC: I'm sure that it is clear for you that we cannot do that. First of all, in this specific scenario that we've encountered, that would mean a downgrade of NLog inside our project, but the biggest problem is: We absolutely do not know what assemblies and what version of those assemblies are installed in the GAC of the customer. I'm sure you realize that, with a big user-base, the installation on each customer's system is unique. Customer A has NLog version X in the GAC because it was installed as a dependency of application 123. Customer B has NLog version Z in the GAC since it was installed as a dependency of application xyz, etc...
Use the NLog source: I certainly won't do that.
That's not simple as this will give many problems to other users because the assembly is strong named.
What kind of problems ? It would certainly solve the issue that we're facing right now. If you have assemblies that are binary incompatible, but have the same AssemblyVersion nr, then you have no real side-by-side installation of different assembly-versions (this is what the GAC tries to solve). In fact, in such a scenario, you're facing DLL hell again.
In certain situations, I can agree that the AssemblyVersion of an assembly remains the same accross versions, but this should only be done when the versions are binary compatible.
As soon as the new version is no longer binary compatible with the previous version, you should modify the AssemblyVersion. This is actually also stated by Semantic Versioning:
Given a version number MAJOR.MINOR.PATCH, increment the:
- MAJOR version when you make incompatible API changes,
- MINOR version when you add functionality in a backwards-compatible manner, and
- PATCH version when you make backwards-compatible bug fixes.
Additional labels for pre-release and build metadata are available as extensions to the MAJOR.MINOR.PATCH format.
(source)[https://semver.org/]
I'd suggest that you should include the minor version in the AssemblyVersion as well.
You should also consider increasing the major version if there's a change that causes binary incompatiblity (for instance, v4.3.5 is binary incompatible with v4.2.3. According to the SemVer rules, v4.3.5 should be have a v5.. version number.
Some applications requires that all assemblies are signed and strong-named. But one is not allowed to depend on multiple version of the same NLog.dll within the same applications. The work-around is keep the version unchanged unless really breaking change (where method-signatures have been removed or changed).
https://nlog-project.org/2015/09/12/nlog-4-1-1-has-been-released.html
You should also consider increasing the major version if there's a change that causes binary incompatiblity (for instance, v4.3.5 is binary incompatible with v4.2.3. According to the SemVer rules, v4.3.5 should be have a v5.. version number.
Pretty sure one is allowed to add extra methods, as long it doesn't change the existing methods. You are apparently using new methods that didn't exist in and older version of NLog.
You can consider to use ILMerge for NLog.dll to always ensure you get the right version independent of what is in the GAC.
I don't understand what issues people might have when you make sure the assembly-version is changed for each new release ?
Because people are using libraries/other project that are using NLog. Please read into strong naming for this question.
- Our solutions doesn't put NLog in the GAC
You can still add the new version to the GAC.
I'd suggest that you should include the minor version in the AssemblyVersion as well.
To be clear, we won't change the schema. This is by design.
Your suggestion to add the new version to the GAC will most likely not work.
Since the assembly-version of both versions is the same, both versions cannot live side-by-side inside the GAC.
The new version might overwrite the existing version and then, our application will work but the other application that uses the older version that was already in the GAC might break.
In my opinion, whenever your existing public API changes , the Major version of the Assemby-version must change (since the new version is no longer binary compatible with the existing version). This is the only way to avoid problems like this in the future.
Your suggestion to add the new version to the GAC will most likely not work.
Since the assembly-version of both versions is the same, both versions cannot live side-by-side inside the GAC.
The new version might overwrite the existing version and then, our application will work but the other application that uses the older version that was already in the GAC might break.
I mean indeed replace. NLog is using Semver, so it should not break.
In my opinion, whenever your existing public API changes , the Major version of the Assemby-version must change (since the new version is no longer binary compatible with the existing version). This is the only way to avoid problems like this in the future.
There is no perfect solution to handle all the strong name issues. With your suggestion NLog would be in version 100+
Another option is to remove NLog form the GAC, and place it in the bin folder for the one that is missing the NLog.dll
@fgheysels This is is the only way to avoid problems like this in the future.
Instead you will have people struggling with implementing binding redirects in their app.config/web.config.
If you don't have control of the runtime-environment, then I suggest that you use ILMerge for the NLog.dll or build it yourself without strong-name support.
Closing this as this is by-design