Debugging Long Compile Times in App_Code directory - asp.net

I have a website based on the .NET 4.0 ASP.net project template. All of a sudden when I'm rebuilding my solution the App_Code directory takes awards of 3-4 minutes to compile (based on what is displayed in the Output window). There are only about 13 classes in this directory and they are all very small.
I've tried to move these files out of the App_Code directory to a separate class library project, but some of them depend on the System.Web.Security namespace which can't be added to a non-website project.
What is the best way to debug this to determine what is bogging-down the compile process?

In case you can't move app_code files due to web dependency to another project then moving them into the same project in another folder will not give you benefit.
Website projects take awhile to build, longer then web app projects.
So, see if you can convert it.
You can also try setting optimizeCompilations="true" under compilation tag.
Change the build project option to compile only the current page on
run or debug
More referencence - https://msdn.microsoft.com/en-us/library/aa730880(VS.80).aspx

Unfortunately the 'App_Code' directory is a black box and you can't watch compilation file-by-file. I tried to migrate to a Web Application template, but this was complicated by the fact that I rely on the Profile provider framework which isn't supported by default.
I think the best solution is to avoid this template entirely. I'm going to deal with the slow compile times until I can migrate entirely to MVC. This is especially important since .NET 5.0 (Core) will not support Web Forms at all.

try set property batch="false", In your Web.config file
< compilation debug="true" targetFramework="4.0" batch="false">

Related

.Net Web Application - Don't precompile

We recently converted a website made with .Net WebForms from a Web Site project, to a Web Application Project.
This is all well and good, except it's now a pain because to change any of our code-behind files we have to rebuild the whole site, whereas before all we had to do was save the code-behind file.
This means changing pages in logged in areas requires not only rebuilding the whole Web Application, but then logging in again for a user.
Is there a way to remove the precompile option while running locally so we can debug as we used to with a Web Site project?
I have tried removing the <compilers> section from the web.config, and also removed the <compilation> too, but neither seem to have made a difference.
EDIT:
I realise now I wasn't very clear. I'm talking about debugging the site locally, not when publishing.
No.
Web Application projects load from a DLL; they have no option to compile source at runtime.
You should specify a fixed validation & decryption keys in Web.config so that users don't need to log in again after deploying (more detail).

Which dll files of ASP.NET web application does IIS load?

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.

Where is the compiled dll for a Website project

One query regarding a Web-Site project in Visual Studio -
I did following steps -
Created a WebSite using VS 2010
Added a custom class in App_Code folder and consumed it in default.aspx
Run the application and I can see the result
Any changes made in server code are reflected on the browser without doing any recompile (website feature)
So, when dynamic recompilation takes place for a web-site, somewhere .net run-time will be storing the compiled dll, isn't it?
Can anyone please guide where I can find the dll being generated during dynamic build are stored? (I just want to know this out of curiosity :-))
Thank you!
P.S. I also did a 'Publish Website' and I can see a bunch of compiled dlls in the publish folder. So, my Question is only regarding dynamic build.
The dynamic created files for your web site are stored on
c:\WINDOWS\Microsoft.NET\Framework\version\Temporary ASP.NET Files\
You can change this directory on the web.config. The asp.net check if any file change on your site and if can find any changes is start the recompile. Also many parameters of the recompile can change on web.config.
How to change this directory
<compilation tempDirectory="" ...>
and this is the rest of the compile options: http://msdn.microsoft.com/en-us/library/s10awwz0(VS.100).aspx
You may find the name & location of Code Gen Directory via property of HttpRuntime.CodegenDir programatically.

When is <Compilation> used in ASP.net

I'm having some trouble setting the ExecutionTimeout element in my applications web.config.
My page is making a lengthy webservice call and times out after 110 seconds. (the default I believe). I set the value to 220, and make sure the compilation debug=false.
Does the compilation setting refer to when IIS/ASP.net compiles the ASPX pages when a client requests them, or does it refer to the visual studio compile process there the assemblies are created.
Would using an assembly built using debug in visual studio still allow the above settings to work?
IIS does not compile aspx pages when people request them. If you have a 'web application project' in VS, you compile all of your code behinds and other class files before you deploy. If you have a 'web site project' in VS, then the web server compiles your app on first request only. After either one of these happen, the application is not compiled again until you make a change.
With that information in mind above, this is when the compilation debug = true | false comes into play. Having debug = true, you get some pretty detailed information back on errors and other events but it can make your app run slower as debug symbols are inserted into the .dll and overall, it is not optimized for performance. By setting debug = false, you don't get quite the same level of error reporting, but you do get your performance gains back.
If you build in VS, it will build according to the settings in the web.config unless it is an external .dll/class project that you are including. If that is the case, the web.config settings mean nothing to that .dll and will run regardless of what combination of debug = false|true you have on those two projects.
Compilation tag is used to add referenced libraries for compilation by IIS or Visual Studio and to specify debug and batch compilation modes.
Speaking of debug attribute, here's good article with all the details in Milan Negovan blog.
And about compilation itself.
There are 3 modes of compilation. They are fully described in MSDN Overview.
By default web application uses updateable precompilation: all .cs files are compiled into one assembly, but all pages, controls and master pages are compiled on demand into new derived class.
Web Site project uses in-place compilation by default.
And non-updateable full precompilation must be specified explicitly. And here when compilation tag comes in. If batch="true" then all pages in application will be compiled upon first request to any page. This moves us to yet another story about big applications :)
Note that there are some other specifics in compilation model, look into ASP.NET Precompilation Overview if you really need this.
IIS compiles ASPX pages (and ASCX UserControls, ASHX, ASMX, ...) the first time they are requested. It also dynamically compiles:
Code in the App_Code folder
Code in code-beside pages for a website project
The compilation element in web.config refers to this compilation.
If you are using a Web Application Project in Visual Studio, your ASPX pages will have a code-behind file. This is compiled into a DLL when the project is built in Visual Studio, and won't be affected by the web.config compilation element.

Updating a DLL in a Production ASP.NET Web Site bin folder

I want to update a class library (a single DLL file) in a production web application. This web app is pre-compiled (published). I read an answer on StackOverflow (sorry, can't seem to find it anymore because the Search function does not work very well), that led me to believe that I could just paste the new DLL in the bin folder and it would be picked up without problems (this would cause the WP to recycle, which is fine with me because we do not use InProc session state).
However, when I tried this, my site blows up and gives a FileLoadException saying that the assembly manifest definition does not match the assembly reference. What in the world is this?! Updating the DLL in Visual Studio and re-deploying the entire site works just fine, but it is a huge pain in the rear. What is the point of having a separate DLL if you have to re-deploy the entire site to implement any changes?
Here's the question: How can I update a DLL on a production web site without breaking the app and without re-deploying all of the files?
The thing to remember is that there are web sites and web applications as far as Visual Studio and ASPNET is considered.
Web Sites typically have all of the aspx and vb files published to the live server and ASPNET Worker Process recompiles the app every time before presentation.
On the other end is the web application, where all of your code behind files get compiled down to a single DLL file and you simply deploy your aspx pages and you bin folder with the DLL file to production.
There is also a "hybrid" known as "Precompiled Web Sites" (see the link for the official MSDN overview) where you don't have the single DLL layout of a web application, but all the compile work of the website is done for you. There are several "modes" to this depending on your needs.
It seems to me that your error is caused because your site is set up as a web site with some kind of precompilation in place. Using the pre-compiled model is a little more "strict" in that is assumes certain files/signatures are in place. Having an updated version of the DLL file causes a break since the precompilation wants a name and a version of the file.
If possible, your best bet would be to convert to a web application, since you can add the additional DLLs into production without a problem. Otherwise, take a look at this matrix to see what form of precompilation you need for your application.
Look at this SO post, might be what you are referring to. The located assembly's manifest definition does not match the assembly reference
Have a look at your reference. Does it say "specific version = true" ? Set it to false, republish your app (you have to do it once, because now your app is still looking for an assembly with a specific manifest) and try it again.

Resources