Why doesn't ASP.NET TempData work when modifying Web.config? - c#

I have a function in my Global.asax.cs file that applies a couple changes to the Web.config file, if needed. The file is saved with:
config.Save(ConfigurationSaveMode.Modified);
I recently discovered that TempData wasn't working for my app: it appeared to be empty on the next request. My MCVE:
public ActionResult Foo()
{
TempData["error"] = "testing error passing";
return RedirectToAction("Bar");
}
public ActionResult Bar()
{
throw new Exception(TempData["error"] as string);
}
I added that to my HomeController, and visiting /Home/Foo would redirect to /Home/Bar. However, with the above config.Save line active, I get:
Server Error in '/' Application.
Exception of type 'System.Exception' was thrown.
But if I comment out that line, I get:
Server Error in '/' Application.
test error passing
as I was expecting originally.
(I had a couple instances where I got the inverse result, but it was usually on the first request after I commented or un-commented the line, so probably I should blame caching.)
Why does this happen, and how can I fix it?

Based from this question:
What happens when I edit web.config?
Imagine each ASP.NET application (as defined in IIS) is a program on
the desktop. Saving web.config will do something similar to closing
the program and reopening it. - Dan Goldstein
IIS default behavior automatically reset entire session state and recycles existing AppDomain when any changes applied to web.config file at runtime, thus all values stored on TempData array are lost, leaving null values instead.
When config.Save line left uncommented, the line:
throw new Exception(TempData["error"] as string);
will contain null value from TempData["error"]:
throw new Exception(null);
Since as operator returns null if the object doesn't exist, it throws new Exception instance with null string, causing default exception message to show instead of custom one.
If config.Save line commented, the configuration changes doesn't applied into web.config file, thus existing AppDomain remains running and TempData values are still in place.
The default behavior can be changed by these steps:
Open IIS Manager.
Select Application Pools => [your application pool name] => Advanced Settings.
On Recycling area, find Disable Recycling for Configuration Changes (DisallowRotationOnConfigChange) section and set it to True.
Related problem: How to prevent an ASP.NET application restarting when the web.config is modified?

TempData stores the values in session and it seems your default session store is InProc which stores the data in server memory which is mainly running under the AppDomain for the Application Pool
By Default, when there is any change in the files under virtual directory, IIS detects that using a File Watcher and recycle the application pool, this will de-allocate all the memory assigned to this web application.
To avoid that, you can change session mode to be either Database or State Server.
But the best thing is to avoid changing the web.config at all, if you have any configuration that is user defined or need to be changed at run time, then you have to store it somewhere else and cache to avoid any performance hits

Related

EF, and why do I have to restart the web site instead of just recycling the app pool?

I have this code in my EF's OnModelCreating() method. It detects whether a table has a column, then binds the right class to EF based on that.
if (new ColumnDetector().AdminColumnExists())
{
modelBuilder.Entity<EntityWithAdmin>();
}
else
{
modelBuilder.Entity<EntityWithoutAdmin>();
}
Initially, the column didn't exist. Then later it was added to the table. The above code doesn't detect it because it already ran. I thought recycling the app pool would do it, but it didn't. Does that make sense? Shouldn't this code run again? I had to restart the web site to get this code to detect the column and set the right class again. Why wouldn't recycling the app pool be enough?

Puzzling differences in behavior between console and web apps

I have a piece of code in a Web API app:
private Stream ConvertWorkBookToStream(WorkBook workBook)
{
var tempFileName = Path.GetTempFileName();
// The following line throws a NullReferenceException
workBook.write(tempFileName);
// Remainder elided for brevity
}
Neither workBook nor tempFileName are null.
On a whim, I changed the app pool to run under a domain administrator account, to eliminate any permissions issues (since I've observed some general wonkiness on my machine of late) and re-ran it. The same exception was thrown.
Then I created a console application and copied the method, verbatim, into the app and ran it. No exception was thrown.
Now, it bears noting that just yesterday, I ran into a similar puzzling behavior regarding File.Exists.
Consider the following call:
var exists = File.Exists(#"\\myshare\\myexistingfile.ext");
Assuming that the path refers to a file that actually exists:
Under a web app, exists returns false on my machine.
The same operation, in a console application, returns true.
My coworkers are experiencing the opposite behaviors.
Can anyone explain this? I'm rather at my wits' end.
Check to see if the return from Path.GetTempFileName is different from the console app and the web app. Windows could be playing tricks with you. I had similar issues attempting to write log files. I just gave up and put them int the same directory as my web service.
In your IIS Authentication settings, are you only having Anonymous Authentication enabled? If I remember correctly Anonymous Authentication impersonates the IUSR account with restricted privileges.

Application_start not working

I have written some code in the application_start() method in my global.asax file. It does not get called when I deploy my application on IIS server. The code is accessible when I run it in the .NET framework.
I've tried to restart the application many times, but it's still not working.
I've also tried the suggestion from the following link.
Application_Start not firing?
There are few things you need to know before you are trying to debug Appplication_Start. There are -
One : When the code executes and why it is almost impossible to debug by attaching to it.
The application start method is executed when the application pool starts and your website is being started up for the first time. If you deploy new deliverables to IIS, then IIS might restart it itself, but there is no guarantee that it will. So, deploying new codes does not guarantee that it will restart the pool and he execution of application start. You should restart your application pool to guarantee execution of application start.
While debugging IIS applications, Visual Studio attaches itself to a process something named w3wp.exe or similart (I forgot the actual executable name), which is the worker process and only available after, remember after, your application pool is up and your site is up. So, in other words, if you are seeing this in service list, then the application start has already been executed and attaching to it will not give you a chance to debug it. It is kind of a tug of war with time.
So, in other words, it is kind of impossible to debug application start unless you are very very quick.
Two, the solution 1 - With Dev Server
Launch your application in visual studio with Asp.net development server or IIS express, then you will be able to debug. But if you really want to debug on IIS, then check the next section
Two, the solution 2 - With IIS
There is a library in the name System.Diagnostics, Debuggerand it has a nice way to call debugger in code. You can read it here - http://msdn.microsoft.com/en-us/library/system.diagnostics.debugger.break(v=vs.110).aspx
Modify you application start with this -
public void Application_Start(){
....... //other codes
Debugger.Break() or Debugger.Launch()
}
When this line executes, IIS will halt execution, and will show you a debugger selector window (similar to the one attached), keep your solution open in vs and select that vs from the list, will be able to debug as usual... :)
In case you are using windows 8 and the debugger does not launch, read this article to enable it -
http://blogs.msdn.com/b/mapo/archive/2013/11/07/debugger-launch-not-displaying-jit-debugger-selection-popup-on-windows-8-8-1.aspx
Three: A very important thing
I noticed that you said, you are adding db entries in Application_Start. You should keep in mind that, Application_Start does not have a HttpContext, ViewContext, So your db access code may fail for so many others reasons.
Make sure that the Global.asax file is actually deployed to the destination folder in the root. If the file is not present then the code behind you have written for Application_Start will never be called.
Also make sure the signature is correct
public class Global : System.Web.HttpApplication {
protected void Application_Start(object sender, EventArgs e) {/*do something here like logging so you know it was called*/}
}
If you are running Server 2008R2 (or earlier) and/or IIS 7.5, you might want to look into the Application Initialization module. This can be downloaded here:
www.iis.net/downloads/microsoft/application-initialization
With IIS versions prior to 8.0, the application start is not called until the first web request arrives. I'm reading your question as you want your application start to be fired before the first web request, yes?
Here is a fantastic guide to configuring this module (if it applies to you):
https://blogs.msdn.microsoft.com/benjaminperkins/2014/01/07/configure-the-iis-application-initialization-module/
The key takeaways is that you need to set your app pool to 'AlwaysRunning' instead of 'OnDemand'. You also need to set a preloadEnabled flag for your website. Once both of these are done, fire off an iisreset and you should see the results of your application start (look in the database since it's writing there).
Other answers are relevant as well, in that this is tough to debug and you're missing all the niceties you're used to such as a httpcontext in app start.
If you are running IIS 8.0 - you should still read the above link to configure preloading.
This did work for me:
Menu -> Build -> Clean Solution
Menu -> Build -> Rebuild Solution
Then, Application_Start() was fired only for the first time.
In my case in production environment App_global.asax.compiled was missing and all content of global.asax not fired.

How to save clicking counter in c#

I build web-site and want to count clicks on some button. I create and try this class of counter:
public static class Counter
{
public static int counter = 0;
}
Every time I click on the button the counter is increament (counter++) ans I see it in my site, But, if I close the chrome and enter again to my site the counter starts from zero.
How can I save the counter? "Static" dont need to do that?
My bet is that it happens because the application space is flushed - it shouldn't reset just because you closed your browser window, thus abandoning the current session (if the session cookie isn't persistent, that is.)
Visual Studio may republish your files (if using a remote IIS) or just plainly restart a local IIS Express instance, depending on how you set your development environment; I do believe setting a specific content as Static would cause it to be available to all current sessions.
That said, you may want to keep it under the current session (using the Session object).
Optionally, if you want to persist information in between server restarts, you may try reading and writing to a local storage, such as a plaintext or XML file. You can find a very nice article about this on the following link:
http://www.codeproject.com/Articles/544839/Implement-ASP-NET-custom-XML-file-configuration
A more sophisticated version would use a local (or remote) database, for example.
Hope it works for you.
static fields are unique per-process. Depending on your application pool configuration, you could have 2, 20 or 100 copies of that.
They're also not thread safe. There are very, very few instances (pun) where a static member is appropriate.
Just off the top of my head, a particular "instance" of a static will disappear when:
The application pool is recycled. On IIS, this defaults to 20 minutes of inactivity.
The application process exits (you may have multiple processes running within your app pool). This happens as part of (1), but will also happen if, say, you're using the Visual Studio debug web server (Cassini), have your project configured to launch the site for debugging, and close the browser that was launched initially. (This happens because VS considers closing the browser that it launched equivalent to saying "I'm done playing. Back to coding now," or hitting the stop button.)
Another thread overwrites the value you've stored (google "race condition.")
You really, really should be storing this in a database. If you're building a website, you need a database anyway. ANYTHING related to application state should be stored in the database.
ALSO, this really, really shouldn't be happening server-side. Are you really performing a postback every time someone clicks anywhere on a page? If so, you have JavaScript in place to handle that, so just skip this insanity, have said script fire off an AJAX request, and have the target handler log it in the database.
Looks like your using a web site so presuming ASP.net. There are a number of ways to store the information. Database could be one or a persistent cookie could be the way to do it. See this article on how to create cookies: How do I set/unset cookie with jQuery?
You can try save it in session and then it will stay until the session is time out(20 minutes) if you want it to long time just write it to file in known location and when you close the web write the value to the file and when the web is up again take the vakue from the file.

Refreshing config file values

I have this strange problem having hard time correcting it. Whenever I update options in my config files it wont detect the changes. I will keep getting exception error saying that option not detected, even i refresh the VS-2012, re start VS02012 and IIS, refesh browsers. It takes long time before it will detect the changes and I can use them. Error I get is
System.Exception: unable to vend object, interface [abc.IExec] reference [option.changeEmployees] ---> System.Exception: option set not found [api_changeEmployees]
While this config file has those options values is saved and updated. What is the fix? Help! Thanks.
Use configuration files for semi-static values, like connection strings, tcp/ip ports. For other settings that should be changed on the fly, use, for example, a ConfigurationTable.
The process actually has to stop and restart to read in new config values. The config values are read in the first time they're accessed and cached in a dictionary for the lifetime of the application.
According to Microsoft though, changing the config file and saving should trigger restarting the application.
If that doesn't work you should be able to just stop and start the app pool hosting your site or issue an IIS reset.

Categories

Resources