I am currently working on a project which requires the use of a custom dll for authentication.
This dll is registered (so they told me) in the GAC of both the Production and Test environments.
The company policies state that you "shouldn't include the dll reference in your application's web.config file", that is, you shouldn't have something like :
<add assembly="" ....="" mydll=""> etc.
in your web.config, at least for this dll I am talking about. They say, since it's registered in the GAC, the application will load it anyway.
The problem is , if you don't add the assemby reference in your web .config , the application is not going to find it , no matter what they say.
Since I am sure the dll is actually registered in the GAC, my question is :
shouldn't the application be able to load the dll anyway , no matter if you add the reference in the web.config or not ?
I was convinced that, adding the reference to the project, the dll 's GAC location would be stored in the application's assembly so that the application itself would be able to find the assembly in the GAC , no matter what the working system is , given that the dll is actually registered in the working system's GAC .
But I must be wrong.
What is the real way it works ?
I tried deleting the <add assembly ...> entry from the web.config : I have a runtime error everytime I reference a method in the dll , in my test environment ; same thing happens in the Production environment;
shouldn't the application be able to load the dll anyway , no matter if you add the reference in the web.config or not ?
By the logic applications would load every assembly in the GAC when they start up, could you imagine how slow that would be? No, that's not how it works.
When you reference a DLL locally in your project, all you are doing is adding it into the manifest which tells the application to load it as part of your application. When the CLR loads, it would first of all check if there is an equivalent version of your DLL in the GAC, if one exists it will load that version, if not it would attempt to load the local version.
See How the Runtime Locates Assemblies
Related
I am developing a .net solution. Due to certain complications, I have been asked to add dlls to the solution and then reference the dlls from within the solution.
It works fine on the local box , and builds perfectly on TFS Build server,
but when I run it on the server after deploying , I get a run time exception saying :
Could not load file or assembly 'Microsoft.TeamFoundation.Client, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies. The system cannot find the file specified.
Would you know what I should be doing at this point ?
I can provide you more detailed info if needed.. please let me know.
It seems like you need to get Microsoft.TeamFoundation.Client.dll file,
then add it as a reference to your application
this is the dependencies you described:
Two possible resolutions
Set CopyLocal property to true so that when build is done local copy of dll is added.
Check reference folder has been checked in TFS or not. Sometimes it happens that reference folder is not added in TFS.
I have a Referenced Assembly where CopyLocal = True, The file is present in the bin folder, but it is not being copied to Temporary ASP.NET Files when I run the solution from Visual Studio
The error message is the usual:
An error occurred loading a configuration file: Could not load file or assembly 'MyNamespace.Configuration, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified.
Solution / Actual Cause
There were a number of problems:
Problem 1: In order to load a configProtectedData Provider, at least in my environment - the assembly must be in the GAC.
The reason for this was revealed by the fusion logs. Although my web app could locate the assembly in the bin folder - the web server (IIS Express) also needs to load it and it was this part that was failing. Since the web server has no knowledge of my bin folder, the only place it can possibly get the file from is the GAC. Fusion shows that IIS Express was having-a-go at looking in Temp ASP .Net folders but I think that this might be some kind of fallback and in my case the shadow copy was indeed copying the assembly but to a different location (Temporary ASP.NET Files\root\4f27e88a\bfcf2f79\assembly\dl3\06324d99\85ff3c73_1943cf01) that IIS Express didn't know to look for.
Problem 2: Once I had the assembly in the GAC properly, (surprise) Typo. I had the class name wrong in the "type" attribute
The thought process to get to the Solution
First: Follow Ivan Niktin's debugging process, Second Fusion Logs are your friend
It makes sense that it is trying to load it from Temporary ASP.Net Files as this is an MVC Web Application.
What doesn't makes sense is that the Temporary ASP.Net Files location that is being searched is empty. If I add the assembly to the GAC then it loads fine, but this is not an option for my deployment scenario.
The Fusion Log shows as the first path searched:
LOG: Attempting download of new URL file:
///C:/Users/Rob/AppData/Local/Temp/Temporary ASP.NET Files/root
/4f27e88a/bfcf2f79/MyNamespace.Configuration.DLL
The other paths are:
.../MyNamespace.Configuration.DLL
.../MyNamespace.Configuration/MyNamespace.Configuration.DLL
.../MyNamespace.Configuration.EXE
.../MyNamespace.Configuration/MyNamespace.Configuration.EXE
When I view the content of the folder that is being searched for the DLL - It is empty!
There is only one namespace involved MyNamespace.Configuration - this is a new / nearly empty assembly with no dependencies other than System.Configuration in the GAC, the host project and referenced assembly are both using .Net Framework 4.0
The part of the application that is trying to load the affected assembly is:
<configProtectedData defaultProvider="DynamicFileConfigurationProvider">
<providers>
<add name="DynamicFileConfigurationProvider"
type="MyNamespace.Configuration.DynamicFileConfigurationProvider,
MyNamespace.Configuration, Version=1.0.0.0, Culture=neutral, PublicKeyToken=aeecd94c462a579a"
SelectorKeyProviderName="HostNameSelectorKeyProvider"/>
</providers>
</configProtectedData>
Update:
Setting shadowCopyBinAssemblies to false had the effect of causing the binder to look at ../Microsoft.NET/Framework/v4.0.30319/Temporary ASP.NET Files/... Rather than the previous IIS Express location
Intercepting the exception earlier did not provide any additional information, simply the same message that the file could not be found.
Referencing the assembly in another host, both console and web turned up no info, the assembly loads fine and the methods can be called.
Manually placing the assembly in the location in which the binder is looking for it also works - It seems to me that the assembly binder is looking in the wrong place. i.e. if shadowCopyBinAssemblies is false, then it should only look in the bin folder. if shadowCopyBinAssemblies is true then the shadow copy location should have my app's dll's as well as any that it references - it shouldn't be empty.
Basically, Temporary ASP.NET Files folder contains assembly copies to allow file updates in the bin folder. When the runtime loads an assembly, it becomes locked and thus you cannot update your assemblies on the server. To solve the problem, the runtime copies them into the "Temporary ASP.NET Files" folder.
I'd try to tackle the problem as following:
Try to disable show copying (<hostingEnvironment shadowCopyBinAssemblies="false" /> or http://msdn.microsoft.com/en-us/library/system.appdomainsetup.shadowcopyfiles.aspx) to check if the problem really relates to Temporary ASP.NET Files.
Try to get more details about the exception using "Break on exception" feature in VS or by using an exception handler. Check exception.Data and .FusionLog properties for more detailed information about the exception.
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler((x, y) =>
{
var exception = y.ExceptionObject as System.IO.FileNotFoundException;
if (exception != null)
// Retrieve exception information here
});
Try to load the problematic assembly in a separate project. Even a simple console app will be fine.
These activities will allow you to narrow cause of the problem.
Not sure about the cause in MVC application, but I encountered a similar kind of issue in my web form based web application where Referenced Assembly where we set to CopyLocal = True. My web project was referencing assemblies both from the GAC and a folder located in the relative path inside the solution.
I resolved the issue by
Removing all the assemblies that were referenced form the relative path
Manually deleted the debug and release folders in both bin and obj folders for all projects.
Added back the assemblies from the local path.
Re-build the project
And things started working. You should probably try these steps as well and this might help resolve the issue.
I have a solution that includes several projects. A few are libs that are building dll's used in my main project in this solution.
My main project builds with output type console application.
This all works fine.
When i change the build output type to a class library (since i want to use this project as a plugin eventually). The project will still build, this time to a dll.
When i use this plugin in an application where i use it as a dll however, it will run up to a certain point where it's trying to load a type defined in an external dll (so NOT built by my solution) and throw the exception:
Could not load type 'externalinterface' from assembly 'externallib, version=3.0.0.0, Culture=neutral, PublicKeyToken=null'.
The dll's are all in the correct folder,etc.
Also worth noting, the plugin is tested in another location than where i built it. The executable still works on this location, the dll/plugin does not. Same amount of dll's in their folders etc.
EDIT: I already used ILSpy (dll inspector) to open the actual dll that is being referenced (so externallib in the errormessage) and checked if 'externalinterface' was present and it is.
EDIT2: RESOLVED! The program that loaded my plugin was loading the same dll that caused the exception. The dll it loaded was of another version than the one i loaded.
Check whether the type externalinterface is present in the referred dll.
You didn't include the details of the exception the application is throwing. However, based on the message you gave, it appears your assembly does not have a strong name. If the application attempting to load your assembly as a plugin does have a strong name, then .NET will require all assemblies loaded by it also have a strong name, so you need to configure your assembly to have a strong name before continuing.
Maybe some supported dll's which is used by the 'externalinterface' is missing in the target machine. In the target machine, check is all the necessary dll's are present in the output folder.
Or blindly copy paste all the dlls in the output folder from the machine where the code is working to the target machine where you have the problem. After this, if the code is working in the target machine, then try to analyze which supporting dll you are missed to copy.
I have a bit of a conundrum with MEF.
I have an installer and configuration application shell which uses MEF to load individual installer components. This gives an end user the ability to select from whatever components have been placed into the install distributable.
The first install components which were written to use this used version 11 of SQLServer SMO libraries. Installing against either 2008R2 or 2012 works fine. (lets call this component A)
I have another team migrating code to a new component but that code uses version 10 of the SQLServer SMO, RMO, and SSIS (DTS) libraries. (lets call this component B)
When MEF goes to load component B I get a LoaderExceptionFailure for one of the SQLServer DLLs (Microsoft.SqlServer.Replication). It actually gives a FileNotFoundException (listing the DLL). The DLL exists in the component's directory. It is the correct version 10.
The shell application already has version 11 files in it.
Is there a way I can tell the application context what to do? Is there a way I can tell the component to load any specific libraries it needs?
I want to assume that each component can specify something "Associated.Library, Version=1.0.0.0, publickey=abcdef123456789, culture=none".
The reason the CLR (not MEF) cannot find the assembly is because it is neither in the GAC, not in the places were the current AppDomain is setup to probe for assemblies.
One way to deal with this kind of problem is to add the missing assembly to the GAC.
Another approach is to add the folder containing the missing assembly to the probing paths of your application. If you don't mind deploying these assemblies in the application base folder (the one containing your executable) then do so. Otherwise you can add deploy it in a sub folder of your application base folder and add the folder to the privatePath element of your app.config.
You will find more information on the article: How the Runtime Locates Assemblies.
I have a COM-visible dll "COMInterface.dll" which is deployed into an existing application's folder. I have created a test harness that has verified the functionality of this dll.
However, when I try to use classic asp to call one of this dll's methods I get a message like the following:
MyCompany.MyProject.COMInterface (0x80070002)
Could not load file or assembly 'MyCompany.Framework, Version=2.6.4202.14897, >Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified.
My "COMInterface.dll" references a number of other dlls such as my company's standard framework, logging classes etc. "Framework" is one of these such dlls.
Where will the asp page be looking for these dlls? I am guessing that my harness worked because it was being run from the program folder whereas the asp page is within an IIS web site.
Do I need to use GAC registration here? I'm hoping not as there would be quite a few dlls I would need to deploy there and I am hoping to extend the application without having to impact the core installation on users' machines.
Thanks in advance of your questions and suggestions.
[EDIT]
I should point out that the object can be created fine. It's the location of the referenced dlls that are causing the problem.
When you use Regasm to register the dll you need to use the /Codebase switch to ensure the dll can be found.
As a general answer, you can use Fusion Log Viewer to determine what paths have been searched by the assembly binder.
See http://msdn.microsoft.com/en-us/library/e74a18c4.aspx for information on this tool.
Fusion Log Viewer will list all the paths probed by the binder. If you put your assembly into any of these paths it will be found. Whether any of these paths will be suitable for your scenario I'm not so sure.