Code to be run automatically when the request is finished? - c#

I have my own SQL based session class. I want to automatically commit the data in the session at the end of program execution (i.e. at the end of serving the page request). Do object destructors (finalizers) not get executed at the end of every request? Is there anyway of doing this instead of having to explicitly call a Dispose() method every time I am done with my session object?

One possibility is by using the global.asax. There is a handler for the end of a request, in C# the call inside global.asax.cs would look something list this:
protected void Application_EndRequest(object sender, EventArgs e){
//perform action - you have access to the HttpContext
}
You have to watch out for what is going through the handler though - depending on your configuration your assets (stylesheet, images, etc.) may also be hitting this request so you may have to devise a way to ensure only your pages have the actions taken on them.

In C#, finalizers are non-deterministic, which means you don't have any guarantee when it will be executed. So, no, you can't use them for your scenario.
I see two ways to approach this:
Programmatically calling Dispose at some point towards the end of the page's life cycle (or via the global.asax as mentioned by Michael G.).
Have your SQL based session class wire itself up to a page event (such as the Unload event) to do whatever actions it wants to clean itself up.
UPDATE:
In response to your question about suggestion #2, I will expound a bit. This option would be to somehow allow your SQL based session class to gain a refernce to the web page instance. One option (which I'll show below) would be to use the constructor of the SQL based session class to obtain a reference to the web page. Then the SQL based session class can sign up for any event that it desires in order to know what is happening to the page.
namespace SomeNamespace
{
using System.Web.UI;
public class SqlBasedSession
{
public SqlBasedSession(Page webPage)
{
webPage.Unload += new EventHandler(webPage_Unload);
}
void webPage_Unload(object sender, EventArgs e)
{
// the web page is being unloaded so this class can
// cleanup it's resources now
}
}
}
Let me know if this still isn't clear.

I would suggest to go with IOC container provider for these kind of stuff. You can hook them up, to the end of a request and execute some code, especially good for some transactional stuff.
I have been using Autofac, it has OnActivated() method, which I use to hook my transaction commits to on activation of session.

Related

Intercept Session Start event for all applications

I have an IIS server (7.5) that hosts several applications each of them run in their own application pool identity. I am trying to write some code that intercepts the Session On Start event. I have successfully written other IHttpModules that are processed for all requests but, in this case I only want to intercept the first time the session is initiated. I want to do this for all the web applications at a global level within my web site. My plan is to use this to capture the last logon date for the user on a per web app basis to satisify an auditing requirement.
I have all the pieces in place except the event that I need to intercept. It seems all IHttpModule Events fire on all requests. I figured the Session_Start event would be ideal but it doesn't look like I can tie into this from an IHttpModule.
I looked at the SessionStateUtility but I do not want to rewrite session functionality, I just want to intercept the start event.
Is there another interface out there I can use to intercept Session_Start? Any other recommendations?
Have you tried something like this?
public void Init(HttpApplication context)
{
var sessionModule = context.Modules["Session"] as SessionStateModule;
if (sessionModule != null)
{
sessionModule.Start += this.Session_Start;
}
}
private void Session_Start(object sender, EventArgs e)
{
// Do whatever you want to do here.
}

How to receive value from an asynchronous method located in a seperate class?

I was working on an application that makes quite a few requests using the HttpWebRequest class to bring back data from the web. Now my app makes nearly identical calls in multiple parts of my application. This is turning into a problem because I'm duplicating a lot of code.
The ideal solution would be to encapsulate the logic that makes the calls to the web in it's own class that way updating is a breeze and it can be reused throughout my application. I'm just not sure how to make an asynchronous call in a separate class and return the value to my main code behind so I can update the UI with the data.
Can someone provide me with some guidance on how to make this happen? I know this has to be possible because developers are doing it all the time when following the MVVM pattern.
I'm using Silverlight/C#.
We have code like this in our Silverlight app for use with WCF Data Services. You could probably do something similar for your web requests:
Here is some sample code (untested) (note that I have not actually ever written any code that does web requests, but maybe the async pattern is similar to other stuff that I have done in Silverlight):
public class WebRequesterHelper
{
Action _callback;
public void MakeWebRequest(object whateverYouNeedForTheWebRequest, Action callback)
{
_callback = callback;
//Make your async web request here, passing the helper object's callback.
IAsyncResult result = yourWebRequestObject.BeginGetResponse(new AsyncResultCallback(WebRequestCallback), yourRequestState);
}
public void WebRequestCallback(IAsyncResult result)
{
//Do whatever you need to do as a result of the web request, then call the callback.
if (_callback != null) callback();
}
}
In your code that wants to make a web request:
var helper = new WebRequestHelper();
//Setup the web request
object request = SetUpYourWebRequest();
helper.MakeWebRequest(request, OnWebRequestCompleted);
Your helper callback:
public void OnWebRequestCompleted()
{
//Web request is finished, what do I want to do?
}
Note that you might want your callback (which you pass to the WebRequestHelper object) to accept a parameter and you could pass information back out from the web request callback function (in the WebRequestHelper object).
Since your web download code is effectively your business logic I would definitely encapsulate it in it's own class as you planned. Then you should use events to notify your UI of state changes.
For example, your "WebRequestManager" instance can encapsulate all the thread handling and will raise events to allow the UI to respond accordingly. You would raise an event on TaskCompleted and perhaps also at intervals to provide looking feedback such as AsyncProgressChanged.
NOTE: By way of convention, I would tend to prefix any events that are likely going to be called from a thread other than the original calling one with the name "Async" so that the UI handler knows to join back onto the UI thread.

MembershipProvider and Caching (NHibernate)

Hey there, I have my own Membership-Provider where I open a NHibernate-Session in the constructor:
public class OwnMembershipProvider : MembershipProvider
{
protected NHibernate.ISession HibSession;
public OwnMembershipProvider ()
{
HibSession = NHibernateTools.OpenSession();
}
//...
I figured out if I set a breakpoint into the constructor, it is called only once during application start. This gives me a headache since the same NHibernate-Session is used for each request, leading to funny things like "oh, i can't change my password" (the NHibernate-Session returns a cached user when calling ValidateUser(), which still contains the old password).
How can I force the framework to reconstruct the MemberShipProvider for each single request? Or how should it be done different?
Thx for any tipps
Opening a separate session in each method sounds like a good idea. Better yet, open one session and transaction for each HTTP request and then commit the transaction when request ends.

asp.net: where to put code to redirect users without a session to the homepage?

I have a web app with loads of pages and most of them require some session variables in order to function.
i want to put some defensive code in my app. where is the best place to put somethign like:
if (Session.Count == 0){
Response.Redirect("~/default.aspx");
}
EDIT: how do i check if the current page is defult.aspx?
Quite difficult, yeah fortunately it is solved.
You need to implement Application_PreRequestHandlerExecute in Global.asax
here is the code
/// <summary>
/// The event occurs just after Initialization of Session, and before Page_Init event
/// </summary>
protected void Application_PreRequestHandlerExecute(Object sender, EventArgs e)
{
// here it checks if session is reuired, as
// .aspx requires session, and session should be available there
// .jpg, or .css doesn't require session so session will be null
// as .jpg, or .css are also http request in any case
// even if you implemented URL Rewritter, or custom IHttp Module
if (Context.Handler is IRequiresSessionState
|| Context.Handler is IReadOnlySessionState)
{
// here is your actual code
// check if session is new one
// or any of your logic
if (Session.IsNewSession
|| Session.Count < 1)
{
// for instance your login page is default.aspx
// it should not be redirected if,
// if the request is for login page (i.e. default.aspx)
if (!Context.Request.Url.AbsoluteUri.ToLower().Contains("/default.aspx"))
{
// redirect to your login page
Context.Response.Redirect("~/default.aspx");
}
}
}
}
Edit 1: Explanation & Conclusion
As one of the guys told about ASP.NET Application Life Cycle.
There are plenty of events that occurs.
Actually events in Global.asax raises in the following sequence
Validate Request // looks just internal mechanism
Perform URL Maping // looks just internal mechanism
Raise the BeginRequest event.
Raise the AuthenticateRequest event.
Raise the PostAuthenticateRequest event.
Raise the AuthorizeRequest event.
Raise the PostAuthorizeRequest event.
Raise the ResolveRequestCache event.
Raise the PostResolveRequestCache event.
Just selects a class who implemented IHttpHandler for the application // looks just internal mechanism
Raise the PostMapRequestHandler event.
Raise the AcquireRequestState event. just before raising this event asp.net loads the State like Session
Raise the PostAcquireRequestState event.
Raise the PreRequestHandlerExecute event.
Call the ProcessRequest method
Conclusion: All the events before AcquireRequestState event don't have Session object, because Session is not loaded by ASP.Net, so any event from *"AcquireRequestState** event gives Session object therefore this problem solves.
However some checks are required as I mentioned in above code
One method would be to have a Page baseclass that performs this check on Page_Init. Another method would be to piggy-back off of #K Ivanov's idea with putting it in the Global.asax. While Session is not available during Application_BeginRequest it should be available in the method Application_AcquireRequestState. For not standard web requests, this should provide access to the session to perform what you want.
in the Application_BeginRequest of the Global.asax
so to summaries the ideas we have:
protected void Application_AcquireRequestState(object sender, EventArgs e)
{
if ((Session.Count == 0) &&
!(Request.Url.AbsolutePath.EndsWith("default.aspx",
StringComparison.InvariantCultureIgnoreCase)))
{
Response.Redirect("~/default.aspx");
}
}
Be careful with your approach.
I don't think it is a good idea to validate globally if certain Session information exists or not. It can get become very messy, very fast. Only certain pages might require specific Session variables, which differ from other pages. Further down the road you might even have some content which can be safely accessed without any existing Session state. Then you will have to start coding exceptions to your rule...
What type of information are you storing in these Session variables? If you elaborate further we could maybe come up with a better approach.
Be careful with Session.Count == 0, because things like Session_ID are, implicitly, stored in the session.
Preferably look for something like (Session["UserName"] == null), where Session["UserName"] is where you, explicitly, store something of the user.
Other than that, Global.asax is the best place (ASP.NET Application Life Cycle).
ALSO, you have to enter a check that you are not currently on ~/default.aspx, because otherwise you will have an infinite loop.

Webservice/WCF (timer update engine)

I am trying to build (csharp) one webservice /WCF engine that make two actions:
Have one timer (thread), that will run in each 10-10 minutes, requesting some information (connecting with other server to grab some info - status) to update in one database. (This must be automatic and no human action will be available). The idea is the webservice automaticaly (10x10 minutes) update the database with the recent information status.
One service method that get some information from one database. (This is one simple method that gives the information when someone request it). This method will responsible to select the status info from database.
The problem is the step 1, because step 2 is very easy.
Can anyone help me, with ideas or some code, how to the step 1.
Any pattern should be used here?
Since it's a webapp (for instance, a "WCF Service Application" project type in VS2010), you can hook into the application events.
By default that project template type doesn't create a Global.asax, so you'll need to "add new item" and choose "Global Application Class" (it won't be available if you already have a Global.asax, FWIW).
Then you can just use the start and end events on the application to start and stop your timer, so something like:
public class Global : System.Web.HttpApplication
{
private static readonly TimeSpan UpdateEngineTimerFrequency = TimeSpan.FromMinutes(10);
private Timer UpdateEngineTimer { get; set; }
private void MyTimerAction(object state)
{
// do engine work here - call other servers, bake cookies, etc.
}
protected void Application_Start(object sender, EventArgs e)
{
this.UpdateEngineTimer = new Timer(MyTimerAction,
null, /* or whatever state object you need to pass */
UpdateEngineTimerFrequency,
UpdateEngineTimerFrequency);
}
protected void Application_End(object sender, EventArgs e)
{
this.UpdateEngineTimer.Dispose();
}
}
The Single Responsibility Principle suggests that you should split these two responsibilities into two services. One (a Windows Service) would handle the Timer. The second, the WCF Service, would have the single operation to query the database and return the data.
These are independent functions, and should be implemented independently.
Additionally, I would recommend against depending on IIS or Application_Start and similar methods. That will prevent your WCF service from being hosted in WAS or some other environment. Keep in mind that WCF is much more flexible than ASMX web services. It doesn't restrict where you host your service. You should think carefully before you place such restrictions on your own service.

Categories