Dll in both the bin and the gac, which one gets used? - asp.net

We have a web application that's deployed to many websites with only frontend changes, the shared backend portion has it's DLL in the GAC so we only have to update that one dll and all the sites get the update.
Is there a way to override the GAC with a DLL in the /bin folder to test out new features before they get released?

If it has the same version number as the referenced DLL, the GAC gets used.
If you increment the version number, rebuild the website referencing the new version number, put the new version in the /bin directory, then that DLL will be used.
If you do not want to change the version number, you're pretty much out of luck.
When .NET loads strong named assemblies, first it tries to decide what version number to use. It does this via the reference first, then it looks for publisher policies, then it looks for binding redirects in the configuration file.
After it does this, it looks for the assembly in the GAC, then in any codebase specified, then it probes various file system folders for the DLL. If at any one of those steps it finds the right version assembly, it stops.
If you are not changing the version number of your strong named assembly, .NET will find the original one in the GAC and stop looking. Note that because it stops when it finds one, and because looking in the GAC is first, specifying a codebase for your assembly will do no good unless you also specify a new version number.

I have been able to override the GAC with the assembly in the \bin folder using the <codebase>Element.
By specifying <codebase version="1.2.3.4" href="/bin/MyAssembly.dll" /> in my web.config file I can tell my application to use this version rather than the version specified in the GAC.
You may also want to take a look at the <probing>Element for specifying assembly locations?

I think I might be saying the same think as Adam Sills, but re-worded it for my understanding. Through my own testing, looks like this is what happens:
If your app is compiled with version 1.0.0.0 and 1.0.0.1 is in the GAC, then you can omit the .dll from your /bin.
If your app is compiled with version 1.0.0.1 and 1.0.0.0 is in the GAC, then you MUST place the .dll in your /bin to ignore the GAC. A error will occur if the GAC version is older than the required version of your app, unless you include the newer version in your /bin.
I hope this is correct...

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).
s

Related

System.Net.Http.Formatting missing in some machines(xml) but works in other (dll)

The best way to include System.Net.Http.Formatting might be through nuget. But when a developer sees it in the default Assemblies section in reference manager then they just add it, expecting all developers to have it installed by default. But to our surprise, some developer machines did not have this dll.
All developers have the correct folder where this dlls is found
"C:\Program Files (x86)\Microsoft ASP.NET\ASP.NET MVC 4\Assemblies\"
Some developers just have XML files and others have dlls in it, even though the file names are the same.
Why are dlls missing in some machines?
Sometimes it is really an issue while finding the missing dlls. Better approach is to clean the nuget cache and folder both and restoring nuget packages again would resolve this issue.
System.Net.Http.Formatting mystery resolved
System.Net.Http.Formatting won't be installed by default along with asp.net. If it appeared in one developer machine, then it could be because some other projects in the VS might have used a nuget to pull it in. This developer without knowing this gives a manual reference to this dll in a new/different project. To him/her everything works fine.
When another/new developer comes and tries to do the same in his/her machine, before reaching this particular project(which pulled in System.Net.Http.Formatting through nuget), the developer gets error(from the manually entered dll project by the previous developer mentioned above). That explains why the dll is missing in his/her machine.
But why is XML file present then?
Becuase the package folder was stored in tfs/git from the first developer machine(who successfully had the dll through nuget). And tfs/git ignored the dll when checked-in.

System.Web.MVC not copied into bin folder since MS14-059. How to protect against creating builds with missing DLLs as a result of Windows Updates?

This morning it was reported that our web app on our QA server was completely broken with the following error reported from Web.config:
Could not load file or assembly 'System.Web.Mvc, Version=5.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' or one of its dependencies. The system cannot find the file specified
Remembering seeing a Windows Update that mentioned MVC, I did some digging and found lots of people reporting a recent Windows Update breaking MVC.
After much digging through those questions and our server, it seems that what's bitten us does not match what's in those other questions, but it does appear related. Here's what we think know:
Our app that is broken uses ASP.NET MVC 5.1
MVC was installed via NuGet
Our BuildServer and QA servers do NOT have MVC 5.1 installed (therefore, not GAC'd)
What we believe has broken caused the "bad build" to be created:
A patch for MVC 5.1 was installed on the BuildServer via Windows Update despite not having MVC 5.1 installed in the GAC
The patch has put the "updated" version of MVC 5.1 in the GAC
CopyLocal=true is ignored when a DLL is in the GAC; therefore since the patch, this means that builds of our app from the BuildServer no longer have System.Web.MVC in the output folder
Since System.Web.MVC is not in the GAC on our QA servers (they have not yet been patched), the application now fails, because System.Web.MVC cannot be found
Assuming the behavior described above is correct, this means that any time MS service a NuGet DLL via Windows Update that we do not have in the GAC, our BuildServer will start producing incomplete builds (missing out those DLLs that have been injected into the GAC).
Upgrading to MVC 5.2 solves this issue (likely because it wasn't patched, and was therefore not injected into the GAC); the DLL is now copied to the output folder. There are no changes in the diff that upgraded to 5.2.2 except for version number changes (there's specifically no <Private> node been added/edited).
We do not wish to start GACing everything, nor creating manual build steps to copy all of our DLLs into the bin folder just in case MS patches them.
So, what can we change today to ensure we don't ever end up with out BuildServer silently producing back bad builds if MS patch other DLLs in the future?
A patch for MVC 5.1 was installed on the BuildServer via Windows Update despite not having MVC 5.1 installed in the GAC
Yes, this behavior is actually by design. See http://blogs.msdn.com/b/dotnet/archive/2014/01/22/net-4-5-1-supports-microsoft-security-updates-for-net-nuget-libraries.aspx.
The patch has put the "updated" version of MVC 5.1 in the GAC
Yes, that's correct; it's how the patch gets the updated code to run instead of the old code. See https://technet.microsoft.com/en-us/library/security/ms14-059.
CopyLocal=true is ignored when a DLL is in the GAC; therefore since the patch, this means that builds of our app from the BuildServer no longer have System.Web.MVC in the output folder
Not exactly. What actually happens is a project that previously was CopyLocal=true gets switched to CopyLocal=false. CopyLocal can be set in one of two ways: 1) If there's an explicit <Private>True</Private> setting in the .csproj file, or 2) By default, if no such setting exists (GAC'd assemblies do not CopyLocal by default; other assemblies do).
So what appears to have happened in this case is that your project file didn't have this setting in the csproj file. As a result, the GUI showed the setting based on the evaluated default value before the patch (CopyLocal = true) but then after the patch was installed, the GUI will now show the new default value for a GAC'd assembly (CopyLocal = false).
Since System.Web.MVC is not in the GAC on our QA servers (they have not yet been patched), the application now fails, because System.Web.MVC cannot be found
That's correct.
Assuming the behavior described above is correct, this means that any time MS service a NuGet DLL via Windows Update that we do not have in the GAC, our BuildServer will start producing incomplete builds (missing out those DLLs that have been injected into the GAC).
For any .csproj reference without an explicit <Private>True</Private> setting, that is correct. Also, note the using NuGet to update your MVC reference can remove this setting even if it was previously present. See http://nuget.codeplex.com/workitem/4344.
Upgrading to MVC 5.2 solves this issue (likely because it wasn't patched, and was therefore not injected into the GAC); the DLL is now copied to the output folder. There are no changes in the diff that upgraded to 5.2.2 except for version number changes (there's specifically no node been added/edited).
That's correct. Since MVC 5.2 is not GAC'd, even without an explicit <Private>True</Private> setting, the default value of this non-GAC'd assembly will be CopyLocal=true.
We do not wish to start GACing everything, nor creating manual build steps to copy all of our DLLs into the bin folder just in case MS patches them.
So, what can we change today to ensure we don't ever end up with out BuildServer silently producing back bad builds if MS patch other DLLs in the future?
The best you can do today is:
Put explicit <Private>True</Private> settings in your .csproj file for all your NuGet package assembly references.
Until NuGet bug #4344 is fixed, any time you use NuGet to update a package reference, go back into your .csproj file and re-add the explicit <Private>True</Private> setting.
I believe this issue is addressed in the .Net Web development tools and UI blog here: link
I won't repeat the whole thing here, as the issue and resolution is explained pretty well at that link.
However just to repeat the key points, which should explain why this has happened:
As part of patch KB2994397 MVC 5.1 was added to the GAC.
There appears to be a NuGet bug that resets CopyLocal flag. (see link ) This means that when a machine with the above patch deploys to a non-patched machine it will break!
MVC 4 has had its assembly version number incremented by the same security update - MS14-059 (so the GAC version will NOT be used) This explains why the MVC 4 version still works - despite it being in the GAC.
I added a note about this issue in my blog:
Microsoft Asp.Net MVC Security Update MS14-059 broke my build!.
Your analysis of the problem is right on the money, by default the Copy Local flag is set to false when the assembly is in the GAC, manually setting it to true should fix this problem.
Upgrading to 5.2.2 is even better, you get the benefits of the new release in addition to the security fix.

ASP.Net build error - assembly not referenced

I am getting a build error when I attempt to build my asp.net application. The error is:
The type 'MediCare.Framework.Authentication.IUserAuthenticate' is defined in an assembly that is not referenced. You must add a reference to assembly 'MediCare.Framework, Version=1.0.1.95, Culture=neutral, PublicKeyToken=1999fa3c42b9'.
I can see the class in the library which is in the references folder. How do I debug this issue?
My intention is to point the references folder to the library source code's bin directory (since the pdb file is lcoated there and any updates to the library will reflect in the application). However, when I point the references folder to the bin directory of the source code, I get the error message above.
Update The application was originally developed in VS 2008 and I am modifying it in 2010. I think I am confused about where the GAC assemblies would be, if I am using VS 2010 (2.0 framework location or 4.0 framework location) ? .NET 4.0 has a new GAC, why?
Update (06-26-2012)
The file in the GAC ("C:\Windows\assembly\") has been deleted. But this error is still occuring.
This could possibly be caused by version inconsistencies. Meaning, in order to fix this, I would do a complete clean build of your assemblies (and also an assemblies that might be nested inside an assembly). Just go out cold and do a new build on all assemblies. That should work.
Go into windows explorer, right click on the DLL file that your project is using that contains this class, and look at the version tab. Make sure version number matches what you see in the error message. My guess is that it won't.
If it does match, then check the GAC and make sure there isn't a different version of the DLL there that it could be picking up. To do that, go to windows explorer, and navigate to c:\windows\assembly. See if that assembly is in there with a different version number. If it is, you may need to delete it from the GAC (use caution though because other apps may depend on it being there).

which dll's are used by an episerver project?

An episerver installation puts the episerver assemblies in the GAC, I see them with C:/windows/assembly.
Besides, all the episerver dll's are present in C:/Program files/Episerver after an episerver installation.
When a create an episerver project via the episerver deployment center or with Visual Studio 2010 using the episerver template, I see that the bin-folder of the newly created project contains a lot of episerver-dlls, which is not very surprising. And I suppose that they are copied from C:/Program files/. If I open the project in visual studio, I see that it's those dll's that are referenced and not the ones from the GAC or from C:/program files/episerver.
Well, all of this is very confusing.
Why is Episerver putting dll's in the gac and not referencing them? What is the best way to handle references to episerver dll's for development in a team?
Moreover, IF episerver would reference the ddl's from the GAC, how would I see that in VS. I mean, what would the properties of the reference be?
Basically, this is all just episerver deployments decisions. I'll try and go over every your question one by one:
Putting dlls into GAC is useful when you want your users to access dlls in the reference dialog from ".NET Framework" tab. Suppose you're creating simple project (not episerver one) and want to add episerver dlls. Instead of looking for them on the hard drive you reference ones that are pointed from the GAC. That's easy for development.
Why not reference GAC dlls ? It's to easier deploy your solution with the dlls. Suppose you're deploying your solution to the server. Server won't be having episerver dlls in the GAC (and shouldn't have, anyway). So they're probably setting "copy local = true" property to copy the dlls into the output folder, making your solution portable. Also, the GAC assemblies aren't "referenced" - GAC just contains copies in a case of need and a reference is added to the "program files" folder with the dlls.
Best way for a development team is to use GAC or to define some kind of "Third Party"("externals") folder in the repository and put your dlls there (and reference from there). First approach requires episerver install on every dev machine, second uses up some space in your repository.
As GAC assemblies can't be referenced (they actually can be, but it's a headache), there is virtually no difference between the result - different paths only.
We usually create a separate directory where we store all .dll-files and reference them from that directory. This means all third party-librarys and episerver-dlls.
The biggest reason for doing this is to avoid a hassle when a new developer needs to setup the project, and also to avoid conflicts between different versions when referencing from GAC.

generating an asp.net web application dll requirement list

I'm trying to set up a web app (32bit on ii7/win7, 32bit setting is enabled, everything is compiled to x86, using vs2008), but there's clearly some dll module loading issue happening. I've been watching procmon and fusion logs but I'm not seeing the name of the missing dll.
I'm a complete newbie to asp.net (but fairly heavy experience on other platforms).
I know I can call depends.exe on a binary to see what the dependancies are, but how do I do it for asp.net? specifically, is it possible to get a list of the dlls that iis7 loads for my application?
update: I manually blew away all of the binaries for my application and rebuilt (clean didnt seem to do the trick, I guess). it's now sort of working. or at least it's getting further and more detailed.
An asp.net web project dll shouldn't depend on anything that is not part of the default .net run-time or explicitly referenced in the project. I would start by reviewing the references. Noramlly an asp.net web project has a bin folder that contains the compiled website/webapplication and any dll's that it depends on (aside from the .net run-time). This is usually done by the programming tool used to create the project.
If you still don't find the culprit, you could try using Filemon (http://technet.microsoft.com/en-gb/sysinternals/bb896642.aspx) and use it to watch IIS to see what files it is looking for and isn't finding.
An additional option is to examine the web.config file that should have been included with the web site/application. Its an XML file and usually has an Assemblies section that lists assemblies that should be loaded. For example you might see:
<assemblies>
<add assembly="MySql.Data, Version=6.2.3.0, Culture=neutral,
PublicKeyToken=C5687FC88969C44D"/>
</assemblies>
This means that the code wants to use the MySQL.Data.dll, and specifically version 6.2.3.0 of that DLL. It is possible to have different versions of .Net dll files installed at the same time. So you might have the desired DLL, but not the correct version as specified in the Web.Config file.

Resources