Why Does a C# Web App ReBuild Result in Application_End() Call? - c#

I noticed that while debugging my applications, sometimes the [InProc] Session State is destroyed following re-builds (C# Web Application). The sequence of events are as follows:
Rebuild & run application (Debug or Release Mode, Doesn't Matter)
Populate a Session Variable in Page_Load() Event
Session_End() fires then Application_End fires()
I perform a postback and check for Session variable populated in Step 2, it is empty.
I am running this application using IIS Express, but it seems to occur irregardless of which web server is being used. This is causing numerous problems as the application isn't counting on Session variables to vanish.
namespace BlankWebApp
{
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
Session["test"] = true;
}
}
protected void butCheckSession_Click(object sender, EventArgs e)
{
if (Session["test"] == null)
{
// Session_End and Application_End must have been called
}
}
}
}

Changing content of bin folder will cause application pool recycling. This is what is happening with the Re-Build, as rebuild will compile the application and create a new dll/executables for the project causing changes in the bin folder. Application pool recycling will cause the session to be removed from server memory.
Similar is true for changing Web.Config file as well.
You can't avoid that. You should have a separate development and production environment.

Related

Initial Loads on ASP.NET MVC Site for every file are slow

I have an ASP.NET MVC website that I have verified that is compiling each time a new C# file (like a controller) is hit for the first time. I have looked at the Task Manager and every first time a new controller is hit, the page is slow, the CPU gets peaked because of the compiler.
I had the Rosyln compiler before but I have switched back the regular C# compiler without any change.
I have tried to precompile but it doesn't seem to matter when I copy my site to the web hosting computer.
I don't remember this happening on the previous version of apps that I worked with but most of those were mostly ASP.NET Forms with MVC throw into the mix.
Is this normal behavior or is this something I can rectify with a setting? I want it to compile all files when the site is first deployed. (In fact, it is so long for the first page I am not sure how it isn't doing this)
Right now, I have a script that hits every controller after I deploy my application which keeps the issue at bay.
To duplicate, just copy a new main dll to your bin folder. Then look at your task manager as you browse to different pages with different controllers.
You can improve your application preference using caching. Please read this article.
Also you can involve application initialization and IIS always running. For this reason you need set startMode of your application pool to always running, this will prevent your application pool from sleeping, after some time.
For more information please read below posts:
iis-80-application-initialization
use-iis-application-initialization-for-keeping-aspnet-apps-alive
you can always pin you application for keeping alive (N:B:- IT's not great idea if you're running in the cloud. But in shared hosting or dedicated server is working fine (tested)).
Example:
public class RecycleConfig
{
public static void PingSite()
{
using (var refresh = new WebClient())
{
try
{
refresh.DownloadString("http://yoursote.com");
}
catch (Exception)
{
}
}
}
public static void SetupRefreshJob()
{
if (HttpContext.Current == null) return;
//remove a previous job
Action remove = HttpContext.Current.Cache["Refresh"] as Action;
if (remove is Action)
{
HttpContext.Current.Cache.Remove("Refresh");
remove.EndInvoke(null);
}
//get the worker
Action work = () =>
{
while (true)
{
Thread.Sleep(600000);
PingSite();
}
};
work.BeginInvoke(null, null);
//add this job to the cache
HttpContext.Current.Cache.Add("Refresh",
work,
null,
Cache.NoAbsoluteExpiration,
Cache.NoSlidingExpiration,
CacheItemPriority.Normal,
(s, o, r) => { SetupRefreshJob(); }
);
}
}
in Global.asax add --
protected void Application_Start()
{
RecycleConfig.SetupRefreshJob();
/........
/........
}
protected void Application_End(object sender, EventArgs e)
{
RecycleConfig.PingSite();
}
Asp.net uses dynamic compilation by default (https://learn.microsoft.com/en-us/previous-versions/bb398860(v=vs.140)?redirectedfrom=MSDN#default-compilation).
You can deploy your site by performing precompilation (https://learn.microsoft.com/en-us/previous-versions/bb398860(v=vs.140)?redirectedfrom=MSDN#performing-precompilation). Deploy your site from visual studio's publish web site tool.
Or you can just enable optimizeCompilations attribute in compilation element in web.config. If its true, asp.net will just compile the modified file, not your whole site.
<compilation targetFramework="4.7.2" optimizeCompilations="true" />

ASP.NET session drop event

Is theire a way, to get noticed if an asp.net web forms session is droped (For example, the client cloeses the browser = timeout)?
We have one session for the temporary user shopping card:
HttpContext.Current.Session["UserShoppingCard"] = new UserShoppingCard();
Every thing works fine, besides the functions explanied above.
Thank you!
I would try to intercept the Session_End event in the global.asax file and put some logging in there, it might not happen right when the browser is closed but it will happen at some point anyway once the session is terminated and you can include your logic in there.
In fact the server never knows when a browser is closed or if instead a connection issue is making the client unable to connect.
As said before, complementing with code...
public class Global : System.Web.HttpApplication
{
protected void Session_End(object sender, EventArgs e)
{
//Do your things here when session ends...
}
}

KeepScreenOnRequest.RequestActive Not Working

For my Windows Store App, I want my application to be active all the time.
I am using code below. My Device set to be go into screen lock in 10 seconds, while I am using my application it still goes into lock screen. Am I using this code incorrectly?
protected override void OnLaunched(LaunchActivatedEventArgs e)
{
// Prevent tablet from sleeping while app is running
Windows.System.Display.DisplayRequest KeepScreenOnRequest = new Windows.System.Display.DisplayRequest();
KeepScreenOnRequest.RequestActive();
}
I think you should try it on page navigation events instead of application level events...
using Windows.System.Display;
private DisplayRequest KeepScreenOnRequest;
protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
if(KeepScreenOnRequest == null)
KeepScreenOnRequest = new DisplayRequest();
KeepScreenOnRequest.RequestActive();
}
protected override void OnNavigatingFrom(NavigatingCancelEventArgs e)
{
base.OnNavigatingFrom(e);
KeepScreenOnRequest.RequestRelease();
}
Again in this scenario you have to handle the request and release part on all of your app's pages individually...
I think the problem may be elsewhere - your DisplayRequest may be garbage collected. Try like this:
Windows.System.Display.DisplayRequest KeepScreenOnRequest;
protected override void OnLaunched(LaunchActivatedEventArgs e)
{
KeepScreenOnRequest = new Windows.System.Display.DisplayRequest();
// Prevent tablet from sleeping while app is running
KeepScreenOnRequest.RequestActive();
}
Few notes:
of course the above code should work for the whole app, when not needed - release the request
putting this in OnNavigatedFrom/OnNavigatedTo may not be a good idea, unless handeled properly - for example when app is suspended (common case) after you return OnNavigated won't be called - your DisplayRequest probably won't be activated
you don't need to worry about releasing you request while the app goes to background, as mentioned at MSDN:
Note Windows automatically deactivates your app's active display requests when it is moved off screen, and re-activates them when your app comes back to the foreground.

My Visual Studio 2008 web application keeps throwing a .Net error when I first run it, but refreshing fixes it

As stated in the title my web application builds successfully, although every time I run it in debug mode I get the following .Net error:
If I hit refresh then the application gets no more errors until I next start it up again, any ideas?
Here is my global.asax file:
<%# Application Language="C#" Inherits="MyCompany.Web.MyApp.Shell.CustomWebClientApplication" %>
<script runat="server">
void Session_End(Object Sender, EventArgs e)
{
FormsAuthentication.SignOut();
}
protected void Session_Start(Object sender, EventArgs e)
{
if (Session.IsNewSession)
{
Response.Redirect(System.Web.Configuration.WebConfigurationManager.AppSettings["HomePage"]);
}
}
protected void Application_Error(Object sender, EventArgs e)
{
System.Exception oops = Server.GetLastError();
//Injection attack error handling
if (oops.GetBaseException() is System.Web.HttpRequestValidationException)
{
Response.Redirect("ErrorPage.aspx");
}
}
</script>
You have something which is trying to access a variable which is set to null (or hasn't been initialized). Do you have anything in the Global.asax or anything that fires on the start of the application? Do you have any asynchronous operations that fire on the start of the application?
Check on your Home.aspx page to see what is happening there. It looks like your application redirects to that page, so I would guess that on either the init or page_load event there is something which is executing that it causing the problem.
System.Exception oops
I think that this is source of problems. When there is no object returned from
Server.GetLastError();
then you will get NullReferenceException on line
oops.GetBaseException()
It makes perfect sense. On first run, oops is null (because no error occured before), thus throwing NullReferenceException. On second page refresh, GetLastError() returns object reffering previous errror (NullReferenceException) and page is displayed. Always check objects for null before accessing them.
Anyway, you can always try catching all runtime exceptions (Debug->Exceptions->Common Language runtime) and see where a problem is.
Sounds like an initialization issue. You're probably trying to use a resource before it's initialized, but by the time you refresh it's had time to be initialized.

Could someone explain this interesting ASP.NET HTTP pipeline events behavior?

It is clear that member variables of an ASP.NET page should lose scope every time the page is refreshed.
I have the following code to display a grid of "Alerts" with edit capabilities:
public partial class Alerts : System.Web.UI.Page
{
private _WikiSyntaxEngine;
protected void Page_Load(object sender, EventArgs e)
{
_WikiSyntaxEngine = new WikiSyntaxEngine();
}
protected void gvAlerts_RowDataBound(object sender, GridViewRowEventArgs e)
{
var alert = (DataModel.Alert)(e.Row.DataItem);
// Below is the only line of interest, because only when published
// to the server would it throw an exception...
string html = _WikiSyntaxEngine.ConvertWikiTextToHTML(alert.Description);
}
}
It was only on the development server to which I published did this code fail (i.e. throws a NullReferenceException because _WikiSyntaxEngine was null) during an update to the row.
However, on my local machine the code runs just fine - the row is updated and the grid refreshes as expected.
I have since fixed the code to make the WikiSyntaxEngine a singleton, or the way it should have been designed from the beginning because it shouldn't have to be instantiated everywhere it is used.
My question then, is how can the Page_Load event be called before gvAlerts_Databound() on my local machine (as expected), but not called on the development machine resulting in the NullReferenceException for _WikiSyntaxEngine?
I'm assuming that your gvAlerts GridView is defined in the ASP.NET markup of the page. If this is the case, it is probably being DataBound in the OnInit() event, not on Page_Load(), where you're instantiating WikiSyntaxEngine.
You probably should use OnInit() to instantiate your WikiSyntaxEngine if your GridView is getting bound before Page_Load.
As for why you're getting different behavior in development and production is still a mystery to me.

Categories

Resources