Glimpse MVC3 DLL being 'forgotten' as part of Application Pool recycle - asp.net

We're trying to get Glimpse up and running in our environment but coming across a strange problem.
We've installed Glimpse.Core, Glimpse.AspNet, and Glimpse.Mvc3.dll and when we configure web.config to enable Glimpse everything works fine until the Application Pool recycles. Once the AppPool recycles, it's as if the site 'forgets' about Glimpse.Mvc3.dll and the Mvc3 tabs (Execution, Model, Metadata) disappear.
Here are the steps (for us) to reproduce:
Modify web.config to include Glimpse configuration
All tabs will show including Execution, Metadata, and Model Binding
Perform an Application Pool recycle
The MVC3 Glimpse tabs will no longer show (but the others will)
Prior to the AppPool recycle, Glimpse.axd shows the following Registered Tabs:
Glimpse.AspNet (1.3.1)
Configuration - Glimpse.AspNet.Tab.Configuration
Environment - Glimpse.AspNet.Tab.Environment
Request - Glimpse.AspNet.Tab.Request
Routes - Glimpse.AspNet.Tab.Routes
Server - Glimpse.AspNet.Tab.Server
Session - Glimpse.AspNet.Tab.Session
Glimpse (1.5.0)
Timeline - Glimpse.Core.Tab.Timeline
Trace - Glimpse.Core.Tab.Trace
Glimpse.Mvc3 (1.3.2)
Execution - Glimpse.Mvc.Tab.Execution
Metadata - Glimpse.Mvc.Tab.Metadata
Model Binding - Glimpse.Mvc.Tab.ModelBinding
Views - Glimpse.Mvc.Tab.Views
And post AppPool recycle, Glimpse.axd shows the following Registered Tabs:
Glimpse.AspNet (1.3.1)
Configuration - Glimpse.AspNet.Tab.Configuration
Environment - Glimpse.AspNet.Tab.Environment
Request - Glimpse.AspNet.Tab.Request
Routes - Glimpse.AspNet.Tab.Routes
Server - Glimpse.AspNet.Tab.Server
Session - Glimpse.AspNet.Tab.Session
Glimpse (1.5.0)
Timeline - Glimpse.Core.Tab.Timeline
Trace - Glimpse.Core.Tab.Trace
It's as if the site is 'forgetting' about Glimpse.Mvc3.dll as part of the AppPool recycle.
Any ideas/suggestions greatly appreciated.

The reason seems to be ASP.Net and the way it loads assemblies from your application directory for the first time and after a recycle. On first start, the assemblies are loaded from your application's bin directory and after a recycle (or even an IIS restart) it loads the assemblies from the Temporary ASP.NET Files directory. And depending on the situation more or less assemblies are loaded.
You can see this for yourself by adding the following lines to your Application_Start method in your Global.asax
protected void Application_Start()
{
Assembly[] loadedAssemblies = AppDomain.CurrentDomain.GetAssemblies();
bool glimpseMvc3AssemblyLoaded = loadedAssemblies.Any(a => a.FullName.Contains("Glimpse.Mvc3"));
File.AppendAllText(
"C:\\temp\\output.txt",
string.Format(
"{0}{1} assemblies loaded and Glimpse.Mvc3 is{2} one of them",
Environment.NewLine,
loadedAssemblies.Length,
glimpseMvc3AssemblyLoaded ? string.Empty : " not"));
}
If you run that then you will see the following entries in your output.txt file (although numbers may differ)
On first initial start:
60 assemblies loaded and Glimpse.Mvc3 is one of them
After recycles
30 assemblies loaded and Glimpse.Mvc3 is not one of them
30 assemblies loaded and Glimpse.Mvc3 is not one of them
After removing the corresponding directory inside the Temporary ASP.NET Files directory
70 assemblies loaded and Glimpse.Mvc3 is one of them
How does this correlate with Glimpse. Well Glimpse makes a call to AppDomain.Current.GetAssemblies() after which it will look for types that implement ITab, but if the Glimpse.Mvc3 assembly isn't returned then tabs defined inside of it won't be discovered and hence not shown.
Does this solve your issue? I'm afraid not, but I think it is better to continue this discussion on the glimpse issue tracker, as a matter of fact I already found a similar issue over there, but I'm not sure if it is yours.
Update
There will be a fix in one of the upcoming releases of Glimpse, but in the meanwhile there is a solution/workaround, as mentioned in one of the comments on the Glimpse issue.
Simply add the following statement to the Global.asax Application_Start method
BuildManager.GetReferencedAssemblies()
and you're good to go

Related

Is it necessary to recycle app pool in order to refresh cached query plans?

I'm not sure if I'm asking the right question exactly, but if you know the answer then you'll probably understand what I'm asking.
I updated a stored proc and tested in dev w/ no problem. So then I updated the proc in production and it caused errors. Took me a bit to figure out what was going on because all I changed was a field in the select list from i.Price to Price = coalesce(r.Price, i.Price). Eventually I figured the only difference could be that r.Price is a decimal value whereas i.Price is a money value so the return type of the field had changed.
Normally that shouldn't matter for c# code. the DataReader value gets cast to decimal either way just fine. But all I had to do to fix the error was reset the app pool and then it worked. I believe I could have also updated my query to cast to a money type and that probably would have worked as well.
I know I've run into this kind of issue a few times before, enough to know there's some kind of caching going on under the hood in asp.net and/or the sql assemblies.
My question is, how can I get this cache to refresh without recycling the app pool. Or is that the only way?
Here what exactly happens when you deploy :
ASP.NET has a feature called shadow copying that enables assemblies that are used in an application domain to be updated without unloading the AppDomain. Normally, this is required because the Common Language Runtime (CLR) will lock the assemblies so you can’t just copy a new assembly over it. Shadow copying means that the original assembly is copied to a temporary location. The copied assembly is locked, and the original assembly can be updated with a new version.
What is assembly interning?
From :
From MSDN:
The ASP.NET shadow copy feature enables assemblies that are used in an application domain to be updated without unloading that AppDomain (necessary because the CLR locks assemblies that are being used). This is done by copying application assemblies to a separate location (either a default CLR-determined location or a user-specified one) and loading the assemblies from that location. This allows the original assembly to be updated while the shadow copy is locked. ASP.NET turns on this feature by default for Bin folder assemblies so that DLLs can continue to be updated while a site is up and running.
https://msdn.microsoft.com/en-us/magazine/hh882452.aspx
App Pool will be recycled automatically when below happens:
Any modifications in the Application’s BIN Directory
Making changes in any Configuration File/s, like Web.config or others ( if you have any specific config file in your application say in a directory called App_Config).
Making modifications in the Source code files in APP_CODE Directory. This maybe change in any Source code files, or adding or deleting files from this directory.
Making changes in the Global.asax file
Making Changes in the Machine.config file.
Making any modifications in the Web Application’s Root Directory. This means creating files/subdirectories on the fly can lead to application pool recycling.
Modifications for references of Web Services of App_WebReferences directory.
Modifying the Security Settings of any directory in the Root directory. (Like specifying read security rights for everyone or any other specific user or user group.)
For more details :
Does any change in any file inside bin folder cause application recycle in ASP.NET web application?

How do I force compilation of ASP.NET MVC views?

I have a Windows Azure web role that contains a web site using ASP.NET MVC. When an HTTP request arrives and a page is first loaded the view (.aspx or .cshtml) is compiled and that takes some time and so the first time a page is served it takes notable longer than later serving the same page.
I've enabled <MvcBuildViews> (described in this answer) to enforce compile-time validation of views, but that doesn't seem to have any effect on their compilation when the site is deployed and running.
Azure web roles have so-called startup tasks and also a special OnStart() method where I can place whatever warmup code, so once I know what to do adding that into the role is not a problem.
Is there a way to force compilation of all views?
Take a look at Precompiled Razor Views by David Ebbo
Why would you want to do that?
One reason to do this is to avoid any runtime hit when your site
starts, since there is nothing left to compile at runtime. This can be
significant in sites with many views.
Also, you no longer need to deploy the cshtml files at all, resulting
in a smaller deployment file set.
Another cool benefit is that it gives you the ability to unit test
your views, which has always been something very difficult with the
standard runtime compilation model. I’ll cover that in more details in
a future post.
Turns out there's ASP.NET Precompilation that can be performed using ClientBuildManager.PrecompileApplication and mimics the on-demand compilation behavior, but just compiles every page. Tried it - the first load looks notably faster.
The non-trivial part is what to pass as ClientBuildManager constructor parameters. The solution is to enumerate all .Applications of the Site object and for each item in .Applications enumerate all .VirtualDirectories and use Path and VirtualPath from each item as parameters to ClientBuildManager constructor.
Is this an initial-load issue or a steady-state issue? One issue seen is that of app pool recycling, which defaults to 20 minute timeout. If you disable timeout (or set it to something large), is that a valid workaround?
Here's another SO answer discussing AppPool timeout and how to disable it. Basically:
%windir%\system32\inetsrv\appcmd set config -section:applicationPools -applicationPoolDefaults.processModel.idleTimeout:00:00:00
Add this to OnStart:
using (var serverManager = new ServerManager())
{
string siteName = RoleEnvironment.CurrentRoleInstance.Id + "_" + "Web";
var siteId = serverManager.Sites[siteName].Id;
var appVirtualDir = $"/LM/W3SVC/{siteId}/ROOT"; // Do not end this with a trailing /
var clientBuildManager = new ClientBuildManager(appVirtualDir, null, null,
new ClientBuildManagerParameter
{
PrecompilationFlags = PrecompilationFlags.Default,
});
clientBuildManager.PrecompileApplication();
}
If you use the Publish functionnality of Visual Studio, there is a much simpler option :
On the Publish dialog > Settings pane, expand File Publish Options and check Precompile during publishing then click configure. On the Advanced Precompile Settings dialog box, uncheck Allow precompiled site to be updatable.
source: https://msdn.microsoft.com/en-us/library/hh475319.aspx

cannot be cast to [B]; Same context (Default); Different Temp File

I'm having difficulty finding why exactly the following error is happening. I'll outline the puzzling aspects below the error description.
[A]ASP.common_resultmessagepanel_ascx cannot be cast to[B]ASP.common_resultmessagepanel_ascx.
Type A originates from 'App_Web_resultmessagepanel.ascx.38131f0b.2c4hpv_z, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'
in the context 'Default' at location
'C:\Windows\Microsoft.NET\Framework\v4.0.30319\Temporary ASP.NET Files\MyWebApp\dc3e0df6\ba1606c8\App_Web_resultmessagepanel.ascx.38131f0b.2c4hpv_z.dll'.
Type B originates from 'App_Web_wz3shqfq, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'
in the context 'Default' at location
'C:\Windows\Microsoft.NET\Framework\v4.0.30319\Temporary ASP.NET Files\MyWebApp\dc3e0df6\ba1606c8\App_Web_wz3shqfq.dll'.
The class referenced in the error is a web user control inheriting from System.Web.UI.UserControl and implementing System.Web.UI.ITextControl. The control is registered and used on a master page. None of the parent master pages or implementing pages have instances of the control. The class and the markup page are both in the web application project. The exception does not happen as a direct result of the application code, it happens during internal .NET Framework code execution. The project is a web application, not a web site. The web application is compiled into a single binary, with culture specific resources compiled into one binary per culture.
The context reported for each type in the exception is the same, but I was able to verify that when the exception occurs there are in fact 2 separate class definitions in the Temporary ASP.NET Files folder for the application.
The user control has always existed and was used in the application, but the exception first started happening after the user control was added to a master page.
The exception does not happen consistently. Once the temporary files get created, the exception will happen every time the page is requested. If anything causes the temporary files to be cleared or recreated, it is random as to whether the duplicate temporary class definitions/DLLs will be created again. This could be a web.config change, recycling the app pool, sometimes even just an updated/rebuilt web application binary.
The last bit of the stack trace:
ASP.Default.__BuildControl__control35(Control ctrl) in C:\Projects\ABC.Web\App_Themes\Default\CheckBox.skin:3
System.Web.UI.ControlSkin.ApplySkin(Control control) +12
System.Web.UI.PageTheme.ApplyControlSkin(Control control) +119
System.Web.UI.Control.ApplyStyleSheetSkin(Page page) +61
ASP.masterpages_mymaster_master.__BuildControlpnlResults() in C:\Projects\ABC.Web\MasterPages\MyMaster.master:10
ASP.masterpages_mymaster_master.__BuildControl__control2(Control __ctrl) in C:\Projects\ABC.Web\MasterPages\MyMaster.master:9
System.Web.UI.CompiledTemplateBuilder.InstantiateIn(Control container) +12
System.Web.UI.MasterPage.InstantiateInContentPlaceHolder(Control contentPlaceHolder, ITemplate template) +87
The supposed offending source (the only line in the skin file C:\Projects\ABC.Web\App_Themes\Default\CheckBox.skin):
<asp:CheckBox runat="server" SkinID="FormInput" CssClass="FormLabel FormInputCheckBox" />
At this point I don't know if this issue is caused by the solution, its configuration, IIS and the app pool, or something related to the actual temp file directory itself where maybe old files are not getting cleared out. I've verified that the temp folder is not being indexed by the OS.
I'm worried that in a production environment, the app pool will recycle or some configuration setting will change and cause those temp files to be recreated with the duplicate class definition, and thus the error. We can't have someone testing the application every time the app pool recycles and deleting temp files if the error occurs until the application loads correctly. So I need to find out what is causing the duplication, but at this point I don't really know where else to investigate.
Any ideas?
I've removed the user control from the master page, and put it directly into each of the pages that required it and were implementing the master page.
So far the exception hasn't happened again. I'm going to give it another couple days of test time to see if it crops up again.
I still want to know why the exception was happening at all. Anyone with in-depth knowledge of how IIS runs .net web apps, or how the temp files are created?
New theory!
While it is a web project with a compiled binary, the IIS instance I am running for development is pointed to the project folder. So the source code files are actually in the web path. I think IIS might be compiling the source code files into separate binaries, especially if the app pool recycles. Thus accounting for the duplicated temp files that are being created and the error.
Other developers were experiencing the errors while running the project from within visual studio. I don't know how this would account for those cases, but I wouldn't rule it out as being the cause either.
I'm not sure what's happening in your case, but I had this happen to me under the following circumstances:
Website project type, not Web Application.
/Controls folder containing many ascx usercontrols.
/Client/Controls folder containing other ascx usercontrols, some of which register and reference /Controls usercontrols.
/Controls/BadControl.ascx using /Client/Controls/DupedControl.ascx as a child control.
The compiler runs into a circular dependency as it tries to compile each folder into a separate assembly.
/Controls/BadControl.ascx needs /Client/Controls to be compiled first.
/Client/Controls needs /Controls to be compiled first.
So the compiler punts and compiles DupedControl.ascx into its own separate assembly first. Then /Controls, then /Client/Controls in which DupedControl still gets included.
At this point there are two distinct Types for DupedControl in two separate assemblies. DupedControl.ascx (markup) points to the correct Type -- let's call it TypeA, in the folder's assembly -- while BadControl's reference points to the dupe TypeB in the small extra assembly.
When a page using BadControl executes, DupedControl TypeA gets instantiated via the markup, but BadControl tries to cram it into a TypeB variable, resulting in the error you described.
The solution is to move ascx files around to get rid of the circular reference. I can't remember for certain, but I think maybe the "single page assemblies" and "fixed naming" options might also resolve it.
All that said, Web Application projects compile to a single assembly, so I didn't think this kind of circular folder reference would be possible. Perhaps the problem lies elsewhere.
After a year and a half of seeing this error intermittently pop up for developers in our team, I've finally been able to gather enough data to draw some conclusions.
The key elements in the scenario causing the error are source code files in the web path, and low available memory on the dev machine that is running the application. The low memory condition causes the application pool to recycle or release memory more frequently than it would in a dedicated web hosting environment. When the memory containing the compiled web app code is released, and then a page is requested, the compiled code is reloaded into app pool memory. Since source code files are in the web path, .NET recompiles from the source code files and reloads into memory.
This situation does not happen in a dedicated hosting environment where only the compiled DLL and static files are deployed, and has never happened in our production environment. Additionally memory usage in a dedicated environment should ideally never reach a point where frequent app pool recycling is necessary.
The Visual Studio solution consists of several projects, and developers typically have multiple VS instances, a SQL Server Mgmt instance, and other sundry processes running which cause low available memory on dev machines. The lower the available memory, the more frequently and reliably the error will happen.
To clear the error state, an application pool flush / iisreset will clear out memory, and then a rebuild will usually fix the problem. If available memory is still low, the problem may persist until more memory is available in which to run the application. Simply closing down some applications or otherwise releasing memory back to the OS should do the trick.
I'm still not sure why running the app through Visual Studio's web server instead of IIS has same issue, but if it handles memory the same way IIS does, it stands to reason that the behavior is the same.
SOLVED!
I had similar problem, caused from LoadControl() strange behaviour.. and solved not instantiating my control before.
strange but true..
MyUserControl myuc = new MyUserControl();
myuo = (MyUserControl)Page.LoadControl("~/UserControls/MyUserCOntrol.ascx");
doesnt work
MyUserControl myuc = (MyUserControl)Page.LoadControl("~/UserControls/MyUserCOntrol.ascx");
works
I belive we found a solution to this problem. We always tried fixing this by deleting the whole "Temporary ASP.NET Files" folder.
At some point this solution would no longer be good enough and the error kept popping up every 30 minutes or so. We found that deleting just the file responsible and then restarting the application pool of the application in question is a permenant fix (at least for us). So for you case you would delete the follwing file (bold) and then restart the applications application pool:
[A]ASP.common_resultmessagepanel_ascx cannot be cast to
[B]ASP.common_resultmessagepanel_ascx.
Type A originates from 'App_Web_resultmessagepanel.ascx.38131f0b.2c4hpv_z, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'
in the context 'Default' at location
'C:\Windows\Microsoft.NET\Framework\v4.0.30319\Temporary ASP.NET Files\MyWebApp\dc3e0df6\ba1606c8\App_Web_resultmessagepanel.ascx.38131f0b.2c4hpv_z.dll'.
Type B originates from 'App_Web_wz3shqfq, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'
in the context 'Default' at location
'C:\Windows\Microsoft.NET\Framework\v4.0.30319\Temporary ASP.NET Files\MyWebApp\dc3e0df6\ba1606c8\App_Web_wz3shqfq.dll'.
This permenantly fixed the problem for us.
EDIT:
Found a permenant solution, at least for us.
In web.config look for tag and add batch="false" to it. So it would look something like:
compilation debug="false" targetFramework="4.7.2" batch="false"
The error never repeated after this.

Unable to retrieve session value

On page load I am populating my own list object, storing in session & it is getting stored, When I am debugging i can see that list object is stored in session, But When I am reading that session variable in next page, it's throwing error like
The type 'Dispensary.ResourceScheduling.Views.SchedulingPopup' exists in both 'WebApplication.dll' and 'App_Web_6bndsqgu.dll'
So Can u please help me how to resolve this issue.
Thanks in advance.
Do a full rebuild on your project.
If that still doesn't work, delete everything in the C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files\[mywebsite] folder, where [mywebsite] is the name of your project. If the DLLs are locked you will have to stop and restart the website in IIS.
Occasionally I've noticed that Visual Studio gets confused and leaves behind the temporary DLLs. This doubles up your classes but is has nothing to do with session values.
You have corrupted .NET temporary files. Before the full rebuild or anything else, do a "Clean Solution". This reliably cleans up .NET temporary files, plus any other accumulated sludge.
Corrupted .NET temporary files can occur from a number of situations, most notably editing binding expressions mixed into markup in .aspx pages. The key to identifying .NET temporary file problems is an obfuscated file name, such as "App_Web_6bndsqgu.dll". Problems can include duplicate .dlls (as noted), inability to find or load some pages and services dynamically (ASP.NET-hosted WCF services are vulnerable to this), and more. So "clean solution" is the first thing to reach for when any of these happen.
When working with source control, it's my basic practice now to do "get latest", "clean solution", and "rebuild solution" before any further work.

Weird MethodNotFound exception when renaming a property - related to asp.net / web forms / fluentnhibernate and visual studio

I have a local website which I run through Visual Studio 2008's internal development web server (through the run / compile button).
I have an external library which is referenced on a page of that website and resides inside the web site's "bin" folder.
I've recently changed a class' property name inside that library (renaming it, from "ValidFrom" to "VisibleFrom"), recompiled its dll and have overwritten the original dll inside the bin folder.
This class is mapped with FluentNHibernate, I've also changed the mappings and recompiled / redeployed the library.
When I try to run the site and navigate to the page where the library is used, I'm getting a MethodNotFound exception for the method get_ValidFrom, related to FluentNHibernate's configuration call. This should be get_VisibleFrom now!
Now I've reconfigured my NHibernate SessionProvider so that it generates a new Configuration for NHibernate on each call, and does not retrieve it from the Http Session entity like it did before, because I figured there might lie the problem.
I'm still getting the exception however. I've then deleted the Temporary ASP.NET folder's content... but I'm still getting the error.
Where is the generated schema for NHibernate stored, when using FluentNHibernate?
Anyone knows where else this could somehow be cached?
Thanks
FNH does not cache the schema, it is generated on-the-fly when you make a call to Fluently.Configure() and the schema is passed directly into an NHibernate Configuration object which is used to build an ISessionFactory.
Try clearing out all compiled objects/libraries/executables, removing the reference to your library from all projects that use it, add it back in, and then re-compile everything. Also check your all your code for "magic strings" that may be referencing this property or causing it to be referenced by the old name.
If that doesn't work, it might be helpful to see a stack trace to get an idea of what is being called from where.

Resources