Where are assembly refernces stored for a web application?
In a Web Site, I see assembly tags written to the assembly node in the web.config when you add a reference. I am just curious as to how the Web Application Project makes the connection to get the correct local dll?
I manually add the reference and the application builds, but the dll is not imported into the BIN folder, and the assembly nodes are not created in the web config as they are in a Web Site. I do a solution search for the text 'assembly="SomeAssembly..." and no results are found.
I am just curious as I am trying to centralize updating assembly references as a 3rd party control vendor puts out hotfixes on a regular basis and we end up having to run around and update all the individual page refernces to the assembly. I was able to do this effectively in the Web Site project, but I am fairly new to Web Application Projects. Any advice or links would be appreciated. I guess I'm looking for tips on assembly & control reference management for ASP.NET Web Application Projects.
Like most Visual Studio projects, references are kept in the project.
There are two kinds of reference:
Project References are references to another project in the same solution. They look like this:
<ProjectReference Include="..\VBClassLibrary1\VBClassLibrary1.vbproj">
<Project>{045D7D9F-8E44-4C4B-95F8-620E86593C5B}</Project>
<Name>VBClassLibrary1</Name>
</ProjectReference>
File references are references to an arbitrary file on disk:
<Reference Include="System.Core">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
If you expand the References folder and click on a reference, then look in the Properties window, you'll see that both kinds of reference have a "Copy Local" property. For project references it defaults to true, for file references to false (though maybe that's only if the file is in the GAC). Changing the default adds:
<Private>False</Private>
Since the assembly was not imported to the BIN folder, and your application works, I assume that it is stored in the GAC (global assembly cache) and marked as "copy local=false" in the reference properties. You don't see the reference to the assembly in the web.config, since your code behind assembly - YourApp.dll (which is always created for web-applications), contains a standard assembly reference to that assembly. When you run your application it loads the assembly from the GAC.
Those "missing" dlls are probably in the Global Assembly Cache and are available to all .NET applications.
You can add control references to the pages/controls section of web.config, which will apply to all pages in the application.
I had the same issue, deleting .vs folder in the directory of the project solved the issue for me as it forced the recreation of .suo file which (though bite code) had reference to the web.config file in the wrong directory
Related
My (C# Asp.net) website works locally, but when I publish it to Azure, it is missing a dll (OpenXML SDK).
After extensive googling, I found that I should set the Copy Local property to True. The thing is though, there is no references node in my solution explorer. Even if I create a new project, and add a few references, there is no references node there. (MS Visual Studio Express 2013 for Web)
Here is the error:
Parser Error Message: Could not load file or assembly [...] The
system cannot find the file specified.
The error is caused by this line (in my Web.config file):
<add assembly="DocumentFormat.OpenXml, Version=2.5.5631.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
Please help me to either:
display the references node
or manually upload the needed dll (feels odd)
or add some magic command to my Web.config to make it automatically upload the used dll-s.
The references node was missing from my Solution Explorer because I chose to create a Web Site, not a Web Application. For Web Sites, the actual physical folder structure is what gets synced to the server. It doesn't have a References node (and, by the looks of it, many other things are missing, since the basic idea is bit different - see this discussion for more details).
There were two solutions for the problem:
Converting my Web Site project into a Web Application project (instructions here)
Adding a Bin folder in my project folder (that is the folder with the project name, the on that has my .aspx files in it), and including the necessary dll in that folder
I chose the latter. After publishing the site again, Visual Studio automatically uploaded the Bin folder with the dll inside it, and it worked like a charm.
I couldn't find any information about it. Does anybody know whether IIS load all dlls in bin directory of web application or all dlls in any directory or maybe only directories referenced by project (in this case how it determines which dll is "master")?
I've just had a situation where someone didn't remove all files from web application directory before deploying new version, while some dll was renamed. This redundant dll was in bin directory of MVC 4 web application.
As an experiment I made a new ASP.NET Webforms project, and deployed it to IIS. I then made a 2nd .net class library, and copied the .dll file to the web app's \bin folder (the class library is not referenced or used anywhere in the ASP.NET app).
I started up SysInternals ProcMon, recycled the app pool and web site in IIS, and requested the site in a browser.
w3wp.exe does indeed read the class library .dll file on first page request.
This MSDN page also states:
You can store compiled assemblies in the Bin folder, and other code anywhere in the web application (such as code for pages) automatically references it. A typical example is that you have the compiled code for a custom class. You can copy the compiled assembly to the Bin folder of your Web application and the class is then available to all pages.
Assemblies in the Bin folder do not need to be installed in the Global Assembly Cache (GAC). The presence of a .dll file in the Bin folder is sufficient for ASP.NET to recognize it.
Which does seem to imply that ASP.NET will reflect over the assemblies it finds in \bin and automatically load them.
Interestingly, even if you put a non-.net file (I copied twain.dll from C:\Windows) into your ASP.NET bin folder, those files are also read. The runtime seems to just ask the filesystem for \bin\* and loops over the files to check for .NET assemblies to load.
I also noticed that if you add this to your web.config file:
<system.web>
<compilation targetFramework="4.5">
<assemblies>
<clear />
</assemblies>
</compilation>
Then the page will no longer run, with the error
Could not load type 'WebApplication1.Global'.
So it seems that the runtime no longer loads those classes from the assemblies. However, the runtime still reads the non-referenced console application .dll and non-.net assembly twain.dll off the drive.
So, the answer comes down to what you mean by "loads all dlls" ... If you mean makes available in the runtime, then the answer is sort-of "no" if you specify your own system.web | compilation | assemblies but the default is to load all. But if you mean what files are physically read, then "yes".
It doesn't load any DLLs automatically.
Every DLL it loads is directly related to a request. First, Global.asax is compiled (which may load some DLLs from bin). Then, whatever HTTP modules and HTTP handlers are defined in web.config (there's some overlap with the previous step). Then the final aspx/asmx/... Some others might go for the ride as part of the configuration or something like that, but all the DLLs that are loaded are always loaded explicitly.
Thus, there is no "master" DLL. web.config, Global.asax and the actual requested file are the ones to decide what's actually going to happen. If you need to have a particular DLL loaded (and you don't simply have it referenced), you need to do it yourself.
EDIT:
Since this is a bit complicated, let me expand a bit.
The main thing to keep in mind here is that ASP.NET is always dynamically compiled - at least to an extent. At the very least, you always have to compile Global.asax - no way around it. Now, dynamic compilation in ASP.NET has an important feature - it's out-of-process (at least for the legacy compiler - I'm not sure about Roslyn+). So whatever the compiler does to find references etc., doesn't actually reflect what's loaded to the worker process itself - and to your application domain in particular.
The dynamic compilation is handled by the BuildManager class on the .NET side - http://referencesource.microsoft.com/#System.Web/Compilation/BuildManager.cs,fb803c621f3806a8. Since you asked about a "master DLL", the most relevant bit would be the code that handles Global.asax compilation, which is one of the starting points of any ASP.NET application. The very initial compilation is handled by the EnsureTopLevelFilesCompiled method. Looking through the code, you can easily see the first steps:
CompileResourcesDirectory();
CompileWebRefDirectory();
CompileCodeDirectories();
...
CompileGlobalAsax();
Most of this is slightly different for web sites vs web projects, as well as for pre-compiled sites, but we can pretty much ignore that. Now, the code isn't the simplest code in the world, but basically, it boils down to producing a bunch of assemblies - about one assembly per code directory. Again, this is done out of process - while the compiler has to load the binaries in bin, they are not necessarily loaded into the ASP.NET worker process. Instead, only the necessary references are actually loaded.
The main thing to take from this is that the dynamic compilation will indeed do a lot of resolving to help you (after all, you don't even know the name of the dynamic assembly where your types are compiled, so you can't specify it!) - but that doesn't mean that all the assemblies in bin are loaded in your ASP.NET application domain. The easiest way to check this is to add an empty assembly that isn't referenced anywhere to bin, and then print out AppDomain.Current.GetAssemblies - you will see that while the file was indeed touched during the compilation process, it wasn't loaded into the ASP.NET application domain. You need to bear this in mind if you ever try to implement some dynamic module loading in ASP.NET - you need to load those assemblies yourself.
You can tweak the way the compilation works in your web.config (especially the global one) - for example, by default, all the assemblies in bin are loaded for compilation purposes, but you can use the system.web/compilation/assemblies tag to cherry pick whatever you want.
Yes asp.net loads any dlls present in your bin directory .
I have recently written a blog on this as I ran into an issue with dlls which were not used in my project. Please refer this blog ,trying to discuss couple of other common scenarios as well.
Asp.net loads all dlls in the bin directory.
I have a solution which contains multiple WAPs (Web Application projects).
Every WAP has it's own Web Deploy project in order to be able to precompile these sites.
On one of the web app we are created a new WCF file with
AspNetCompatibilityRequirementsMode.Allowed
In debug mode it is working ok, but if i switch to release it crashes:
(we are using msbuild to create the deployable versions)
Could not load file or assembly 'App_Web_*****, Version=0.0.0.0,
Culture=neutral, PublicKeyToken=null' or one of its dependencies. The
system cannot find the file specified.
I found some explanation in this link: WCF service
WCF stores the list of referenced assemblies into the customString
attribute in the build result (service.svc.cdcab7d2.compiled),
including App_Global. It seems there is an incorrect assumption here
that those assemblies will always be there, which is not necessarily
the case in Web Deployment Projects (aspnet_merge) where assemblies
will be merged. After the merge step, the assemblies are actually all
merged into a single assembly (let us say MyWebSite.dll) as we
selected that option in WDP. ASP.NET only updates the .compiled files
it knows about, so App_Global.asax.compiled actually has a correct
reference to MyWebSite_Deploy.dll instead of App_Global.dll. Original
assemblies are removed after the merge step. WCF reads the list of
assemblies previously stored, and throws when it cannot find
App_Global
List of solutions i've tried:
1.Check 'Allow this precompiled site to be updatable' - not worked
2.Remove manualy the App_* reference from service.compile file
(It worked but it should be another solution)
3.Add fully qualified name for the service/factory in .svc
The service has a fully qualified name.
4.tried to set this key:
<SourceWebPhysicalPath>..\..\ProjectName</SourceWebPhysicalPath>
following these instructions
5.<compilation debug="false" batch="false">
Tried this to set to web.config using these instructions
6."Merge All outputs to a single assembly"
i haven't tried this because it requires to register all the used assemblies to GAC and means we need to change the deployment logic.
I don't want to delete the asp.net temporary folder because it stops the application and it is inacceptable
I also found Scott Gutthrie link but it's from '07 it should made it's way to asp.net 4.0
Additional Info
The service is placed: ProjectName\WebResorce\Service.svc ,
<%# ServiceHost ... Factory="SolutionName.SharedWeb.WadoLabsServiceHostFactory" %>
where the SharedWeb is a Shared Web project
Do you have any other ideas?
Thanks in advance
The following setup worked for me:
In the svc file, specify a qualified name of the service, as <%# ServiceHost ... Service="<Namespace>.<ServiceContractClass>, <AssemblyName>" CodeBehind="ServiceContractClass.svc.vb" %>
(Can't remember why it was required, but) I made sure that the Namespace and the AssemblyName are different.
The trick is to specify the qualified name, including the AsseblyName.(The assembly name that is specified in the project containing the service, not the Web Deploy Project).
Also note that there is a space between the comma after the class name, and the AssemblyName.
Why don't you implement the WCF services in a separate library project inside the same solution, and simply reference that project from your web app(s)? That way they would stay out of the pre-compilation process, and you could work with predictable type names inside the *.svc files. Plus, this would probably also give you a cleaner solution structure.
When you use ASP.NET web site (instead of web application model) and add reference to an assembly from local folder, Visual Studio, it seems, understands that this local assembly is also in GAC and so does NOT copy this assembly to bin folder (as it does with non-GAC assemblies), but simply adds new record in web.config file.
Why such a behaviour? Is it possible to force copy to bin folder (I need this since .dll is not on target environment)? I can add assembly to bin folder as file and it will work, but in this case bin folder contents will be in source control, which is not good.
You can set the Copy Local property to True on the reference. That should add it to the bin folder - on a Web Application project.
But for a Web Site project, when you add a reference, all it does is add a line to the web.config that references the assembly. It will look for this file first in the bin folder, and then in the GAC if it is not found.
You have two options: require the assembly to be installed in the GAC on the target machine (in which case, XCOPY deployment is not possible) or include all required assemblies in the bin folder, either by copying them in or writing a post-build script that does so. You can find the .dll by using the command prompt and going to c:\windows\assembly\GAC, find the assembly you are interested in, cd into that directory and then cd into the directory with the version you are interested in. This will give you the path to use in your post-build script. For example, for the Accessibility assembly in the GAC, you'd end up with this path:
c:\Windows\assembly\GAC\Accessibility\1.0.5000.0__b03f5f7f11d50a3a\Accessibility.dll
You say including the bin folder contents in source control is not good. This is generally regarded as true for binaries you build, but in your case, you have binary assets that are not compiled as part of your project. Philosophically, these are equivalent to images: binary assets not compiled as part of your project. I would argue they belong in source control as much as any other binary your project relies on. But it is a personal choice.
If you are using a website project in Visual Studio and a reference keeps pointing it to the GAC version instead of some other folder (eg lib), you will need to create a xxxx.dll.refresh file in your /bin folder, where xxxx is the offending dll you are referencing.
This will resolve build problems with MSBuild too where the server will expect the dll to be in the GAC. The .refresh file will get the file from the correct relative path to do builds correctly.
At run time, assemblies must be in one of two locations: the output path of the project or the global assembly cache (see Working with Assemblies and the Global Assembly Cache). If the project contains a reference to an object that is not in one of these locations, then when the project is built, the reference must be copied to the output path of the project. The CopyLocal property indicates whether this copy needs to be made. If the value is true, the reference is copied. If false, the reference is not copied.
The project-assigned value of CopyLocal is determined in the following order:
If the reference is another project, called a project-to-project reference, then the value is true.
If the assembly is found in the global assembly cache, the value is false.
As a special case, the value for the mscorlib.dll reference is false.
If the assembly is found in the Framework SDK folder, then the value is false.
Otherwise, the value is true.
Hope this helps
s
For information on how to set the Copy Local Property of a Reference for a web project (not a web application), see:
http://msdn.microsoft.com/en-us/library/t1zz5y8c(v=VS.100).aspx
In order to make use of GetGlobalResourceObject() in Visual Studio 2008 I have to copy a .resx file into the folder App_GlobalResources of Visual Studio. After the application is precompiled, the resource files are being compiled into the corresponding satellite assemblies and deployed under the \bin\ folder by culture names. This all works fine.
However, I'm unable to add new satellite assemblies after the application has been precompiled. What I've done was:
Created a satellite assembly:
resgen resources.applicationresources.es-ES.resx resources.applicationresources.es-ES.resources
al /t:lib /culture:es-ES /embed:resources.applicationresources.es-ES.resources /out:App_GlobalResources.resources.dll
Created folder \bin\es-ES\ and deployed the .dll file there.
Unfortunately, the newly added satellite assembly is not being recognized by the GetGlobalResourceObject(), which falls back to the default (English) resource. There seems to be nothing wrong with the resource file because if I copy the same .resx file into App_GlobalResources and then compile the application, everything works just fine.
What am I missing? BTW my project type is website and not web application project.
(From Comment by #ksa)
One thing that can go wrong is an incorrect namespace path in the DLL produced by resgen, you can use ILDASM or Reflector to compare the namespaces in the working DLLs and the generated not working DLLS. You can then change your resgen command line to generate with the correct namespace.
Try hooking up to the AssemblyResolve event in AppDomain.CurrentDomain and see if it's actualy looking for the assembly. If it does look for it, all you need to do is keep a list of dynamically loaded assemblies and their paths.
One note about AssemblyResolve, if you don't have the assembly, return null. That's the default behavior.