.NET compiled third-party DLL reference conflict - c#

I am using Umbraco (a .NET CMS), and it has a reference to a specific version of a DLL (see 1 Umbraco Reference below). This is fine until I try to hook into the .NET MailChimp API which references a different vesion of the same DLL (see 2 PerceptiveMCAPI below).
I can think of a couple of options for resolving this
a. Get either the Umbraco or PerceptiveMCAPI source and reference the same version of the DLL, really do not want to do this for compatibility reasons
b. Dump the 2 DLLs in the GAC, I want to avoid this as I see deployment issues arising if someone forgets (I know we should have an automated deployment but time is restricted)
I remember that there is a third option to specify what version of the DLL to use in the configuration. Is this possible and what is the code for it?
1 Umbraco Reference
// Assembly Reference CookComputing.XmlRpcV2
Version: 2.4.0.0
Name: CookComputing.XmlRpcV2, Version=2.4.0.0, Culture=neutral, PublicKeyToken=a7d6e17aa302004d
2 PerceptiveMCAPI
// Assembly PerceptiveMCAPI, Version 1.2.4.3
Location: C:\Work\AEGPL\AEGPL_Website\bin\PerceptiveMCAPI.dll
Name: PerceptiveMCAPI, Version=1.2.4.3, Culture=neutral, PublicKeyToken=null
Type: Library

This is exactly the reason the GAC exists. The only other workaround I can think of is to stuff these DLLs in subdirectories so the CLR cannot find them and implement AppDomain.AssemblyResolve. You now get to maintain that code for every new version update.

Related

ASP.NET web site builds locally, but throws MSB3268 on the build server

I added a project to my web site solution. Everything built fine locally and on the build server.
I added a line in web code to call a method in the new project. Everything built and worked fine locally, but it broke the build on the build server.
I got a pile of errors going something like this:
warning MSB3268: The primary reference "C:...\ProjectName.dll" could not be resolved because it has an indirect dependency on the framework assembly "Assembly.Name (e.g. System.Runtime)", Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" which could not be resolved in the currently targeted framework. ".NETFramework,Version=v4.5". To resolve this problem, either remove the reference "C:...\ProjectName.dll" or retarget your application to a framework version which contains "System.Runtime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a".
After all the warnings, the build failed with an error indicating the namespace ProjectName could not be found. Makes sense considering the project's dependencies couldn't be resolved.
At first I wondered if there was an issue with targeting the wrong framework. But there was a mix of 4.0 and 4.5 projects referenced by the 4.5 website. This was the first one that had failed.
The only difference between this and the other projects was that it referenced third-party DLLs. So apparently their dependencies are the ones that couldn't be resolved.
This post held the key: http://devsilos.blogspot.com/2014/10/msb3268-while-targeting-aspnet-web-site.html
The author suggests:
aspnet_compiler for some reason does not take into account the .dll-s that reside under the Facade directory of 4.5 assemblies (C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework.NETFramework\v4.5\Facades).
It looks only under
C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework.NETFramework\v4.5
My extrapolation on that idea is that maybe the compiler doesn't take into account DDLs in the Facades directory if they're referenced by a third-party DLL rather than directly from your project.
The solution, as suggested by the author, was to find the DLLs matching assemblies mentioned in the MSB3268 warnings and copy them from Facades to its parent directory.
I think my problem/solution differed from the blog's in that it had nothing to do with the .NET Framework version targeted. It had only to do with whether the build server's compiler looked in the right places to resolve third-party DLLs' dependencies.
The problem caused about ten hours of frustration. I hope this helps someone else avoid that!

Use .net DLL with broken References

I have to use a DLL as an API in my application (C#, .NET 4.5). I can reference the DLL normaly. No error at all. But if I want to use any class of this DLL, I get the following compile error:
Error CS1705 Assembly 'Assembly_X' with identity 'Assembly_X,
Version=12.3.0.0, Culture=neutral, PublicKeyToken=c878e80841e75d00'
uses 'Assembly_YY, Version=65535.65535.65535.65535, Culture=neutral,
PublicKeyToken=c878e80841e75d00' which has a higher version than
referenced assembly 'Assembly_YY' with identity 'Assembly_YY,
Version=12.3.0.0, Culture=neutral, PublicKeyToken=c878e80841e75d00'
Then i checked the DLL (Assembly_X) in ILSpy. The Assembly_X has two references to Assembly_YY: One with the version 12.3.0.0 and one with the version 65535.65535.65535.65535.
I tried the "bindingRedirect" in the App.config. But since the error occures during compile time this doesn't help.
I don't have the source code of Assembly_X or Assembly_YY.
How can I use this DLL or repair it?
UPDATE
The developers of the dll finally answered my call for help. The only work around they know of is to use Visual Studio 2013 instead of Visual Studio 2015 or 2017. It seems VS 2013 is not bothered by these double reference at all.
They write, that the error is created by a encrypting tool for the dll.
Thank you all for your ideas and help.
It looks like the first DLL is referencing a library which is a higher version than the other DLL you are using.
so you have 3 DLL's to consider: A, B & Bv2
Your project is referencing A & B
But A references Bv2 (an updated version of B)
SO when you go to use functions of A it throws an error because it finds B instead of Bv2.
The problem basically that you are referencing 'Assembly_X' which references assemblies 'Assembly_YY' versions 12.3.0.0 and 65535.65535.65535.65535 and you referenced only 'Assembly_YY' version 12.3.0.0 in your application and didn't reference 65535.65535.65535.65535
Now according to the problem explanation on Microsoft Docs, and your example which you don't have the source code for the assemblies you have to:
Add a reference to 'Assembly_YY' version 65535.65535.65535.65535 of the DLL to your application to make it compile and to enable the application to run, you can provide an application configuration file that includes a <dependentAssembly> element that uses <assemblyIdentity> and <codeBase> child elements to specify the location of version 12.3.0.0 of the DLL.
You are referencing a higher version of DLL then the one you currently have.
You will need to add the reference to the higher version assembly:
'Assembly_YY, Version=65535.65535.65535.65535, Culture=neutral, PublicKeyToken=c878e80841e75d00'
in order to solve this.
Right now you are referencing
'Assembly_X' with identity 'Assembly_X, Version=12.3.0.0, Culture=neutral, PublicKeyToken=c878e80841e75d0
If this is a downloadable library, search for it in the nuget package manager and download it.
If it's a library written by you, obtain the latest version of the library and add it to your project.

How do I create and use a .NET metadata-only 'Reference Assembly'?

Since version 3.0, .NET installs a bunch of different 'reference assemblies' under C:\Program Files\Reference Assemblies\Microsoft...., to support different profiles (say .NET 3.5 client profile, Silverlight profile). Each of these is a proper .NET assembly that contains only metadata - no IL code - and each assembly is marked with the ReferenceAssemblyAttribute. The metadata is restricted to those types and member available under the applicable profile - that's how intellisense shows a restricted set of types and members. The reference assemblies are not used at runtime.
I learnt a bit about it from this blog post.
I'd like to create and use such a reference assembly for my library.
How do I create a metadata-only assembly - is there some compiler flag or ildasm post-processor?
Are there attributes that control which types are exported to different 'profiles'?
How does the reference assembly resolution at runtime - if I had the reference assembly present in my application directory instead of the 'real' assembly, and not in the GAC at all, would probing continue and my AssemblyResolve event fire so that I can supply the actual assembly at runtime?
Any ideas or pointers to where I could learn more about this would be greatly appreciated.
Update: Looking around a bit, I see the .NET 3.0 'reference assemblies' do seem to have some code, and the Reference Assembly attribute was only added in .NET 4.0. So the behaviour might have changed a bit with the new runtime.
Why? For my Excel-DNA ( http://exceldna.codeplex.com ) add-in library, I create single-file .xll add-in by packing the referenced assemblies into the .xll file as resources. The packed assemblies include the user's add-in code, as well as the Excel-DNA managed library (which might be referenced by the user's assembly).
It sounds rather complicated, but works wonderfully well most of the time - the add-in is a single small file, so no installation of distribution issues. I run into (not unexpected) problems because of different versions - if there is an old version of the Excel-DNA managed library as a file, the runtime will load that instead of the packed one (I never get a chance to interfere with the loading).
I hope to make a reference assembly for my Excel-DNA managed part that users can point to when compiling their add-ins. But if they mistakenly have a version of this assembly at runtime, the runtime should fail to load it, and give me a chance to load the real assembly from resources.
To create a reference assembly, you would add this line to your AssemblyInfo.cs file:
[assembly: ReferenceAssembly]
To load others, you can reference them as usual from your VisualStudio project references, or dynamically at runtime using:
Assembly.ReflectionOnlyLoad()
or
Assembly.ReflectionOnlyLoadFrom()
If you have added a reference to a metadata/reference assembly using VisualStudio, then intellisense and building your project will work just fine, however if you try to execute your application against one, you will get an error:
System.BadImageFormatException: Cannot load a reference assembly for execution.
So the expectation is that at runtime you would substitute in a real assembly that has the same metadata signature.
If you have loaded an assembly dynamically with Assembly.ReflectionOnlyLoad() then you can only do all the reflection operations against it (read the types, methods, properties, attributes, etc, but can not dynamically invoke any of them).
I am curious as to what your use case is for creating a metadata-only assembly. I've never had to do that before, and would love to know if you have found some interesting use for them...
If you are still interested in this possibility, I've made a fork of the il-repack project based on Mono.Cecil which accepts a "/meta" command line argument to generate a metadata only assembly for the public and protected types.
https://github.com/KarimLUCCIN/il-repack/tree/xna
(I tried it on the full XNA Framework and its working afaik ...)
Yes, this is new for .NET 4.0. I'm fairly sure this was done to avoid the nasty versioning problems in the .NET 2.0 service packs. Best example is the WaitHandle.WaitOne(int) overload, added and documented in SP2. A popular overload because it avoids having to guess at the proper value for *exitContext" in the WaitOne(int, bool) overload. Problem is, the program bombs when it is run on a version of 2.0 that's older than SP2. Not a happy diagnostic either. Isolating the reference assemblies ensures that this can't happen again.
I think those reference assemblies were created by starting from a copy of the compiled assemblies (like it was done in previous versions) and running them through a tool that strips the IL from the assembly. That tool is however not available to us, nothing in the bin/netfx 4.0 tools Windows 7.1 SDK subdirectory that could do this. Not exactly a tool that gets used often so it is probably not production quality :)
You might have luck with the Cecil Library (from Mono); I think the implementation allows ILMerge functionality, it might just as well write metadata only assemblies.
I have scanned the code base (documentation is sparse), but haven't found any obvious clues yet...
YYMV

"Could not load file or assembly 'Microsoft.Practices.EnterpriseLibrary.Validation" exception

I am currently getting the following exception while trying to use the Enterprise Library Validation Application Block:
An error occurred creating the configuration section handler for validation: Could not load file or assembly 'Microsoft.Practices.EnterpriseLibrary.Validation, Version=4.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040) (C:\Documents and Settings\My Documents\Visual Studio 2008\Projects\Testers\TestProject\web.config line 12)
I know what the exception is trying to tell me, but I can't figure out how to fix it. I have only ever installed one version of the Enterprise Library, and this is it (4.1.0.0), so I don't see how it could be finding the wrong version, so I imagine it is then a dependency problem. I have included the "Common", "Validation" and "ObjectBuilder2" DLLs from the Enterprise Library 4.1 as references in the project, so I'm not sure what else I'm missing. The documentation certainly seems to indicate this is all I need.
Is there any way to track down what the dependency problem is?
If it helps, I am trying to use the Enterprise Library Configuration Tool to create a Validation Application Block rule set for validation of data in an Entity Framework entity. I am using ASP.NET MVC in Visual Studio 2008.
Thanks for any assistance/direction you can provide,
Chris
Turn on Fusion logging and see what assembly is being bound at runtime.
Hanselman had a post recently that should be helpful in enabling logging and examining the output.
http://www.hanselman.com/blog/CommentView.aspx?guid=3654c8f3-c5c3-4dee-a01f-c9a8da3ef2fa
Another important distinction to make is that references that are added to the project are compile-time references and don't affect the way that code is bound at runtime other than to specify a strong name if a strongly named assembly was used. In order to find out what is happening at runtime you need to look at the binding logs. The log should show you all of the attempts that the runtime makes at locating the assembly. If the assembly is not in the bin directory along with your exectuable, it is most likely looking in the GAC and finding a version that it does not expect.
Note that the compiler DOES NOT use the GAC when referencing assemblies. So most probably you have a different version used as a reference in the project than you have installed in the GAC.
Also, it is very easy to find out what version you have installed in the GAC by looking in C:\Windows\assembly using Windows Explorer. The version that is specified in your error message will be the version that was referenced during compilation. If these versions don't match this could be your problem, assuming that Fusion is indeed looking in the GAC (which will be evident by looking in the Fusion log).

How to prevent a .NET application from loading/referencing an assembly from the GAC?

Can I configure a .NET application in a way (settings in Visual Studio) that it references a "local" assembly (not in GAC) instead of an assembly within the GAC, although both assemblies have the same name and the same version?
If both assemblies are strong-named (signed), the CLR will always load from the GAC.
Here are the steps the runtime uses to resolve assembly references (from How the Runtime Locates Assemblies):
Determines the correct assembly version by examining applicable
configuration files, including the
application configuration file,
publisher policy file, and machine
configuration file. If the
configuration file is located on a
remote machine, the runtime must
locate and download the application
configuration file first.
Checks whether the assembly name has been bound to before and, if so,
uses the previously loaded assembly.
If a previous request to load the
assembly failed, the request fails
immediately without attempting to load
the assembly.
Checks the global assembly cache. If the assembly is found there, the
runtime uses this assembly.
Probes for the assembly (... some material omitted ...)
As stated later in that same article:
There is no version checking for assemblies without strong names, nor does the runtime
check in the global assembly cache for assemblies without strong names.
So if you can afford to remove signing from the local assembly, the application will use it instead of the one in the GAC.
For more detail than you could probably ever want about the runtime-binding mechanisms, see Suzanne Cook's blog.
This blog entry from Scott Hanselman also provides a great overview of the binding process.
If you can change the version number of the local dll, you can use a dll version redirect using the oldVersion attribute. You can use a strong name for the local assembly:
Please look this page:
http://msdn.microsoft.com/en-us/library/7wd6ex19.aspx
Also you should consider that it is possible to modify the version number of a compiled assembly like it is described here:
Change Assembly Version in a compiled .NET assembly
You can use ilmerge and merged the assemblies into a single library to get around it.
To successfully deploy your .NET Framework application, you must understand how the common language runtime locates and binds to the assemblies that make up your application. By default, the runtime attempts to bind with the exact version of an assembly that the application was built with. This default behavior can be overridden by configuration file settings.
You can view binding information in the log file using the Assembly Binding Log Viewer (Fuslogvw.exe), which is included in the Windows Software Development Kit (SDK).

Categories

Resources