Call a method in application scope (.Net) - asp.net

I have a UserControl(uc) in my master page, and a method(MyMethod) inside uc that make some calculations.
protected void Page_Load()
{
If(!IsPostBack)
MyMethod();
}
private void MyMethod()
{
SomeCalculations..
}
Because my uc is in master page, i can see the uc in all my aspx pages. My aim is that as soon as a user login the application, run MyMethod() just once (in a thread) and do calculations in an infinite loop until the user logout or application (or browser) closed. Although the calculations are outside of the PostBack, MyMethod will be called more than one time.
Assume that I m in Page-1 and it s loaded first time, MyMethod() will bi called. After another page (Page-2) is loaded, MyMethod will be called again and I want to prevent it. Is there a way to do something like this:
if(LifeCycle of application resumes)
{
MyMethod()
}

You can store a flag in application state and use it in a condition. Something like this, perhaps:
// in Application_Start in Global.asax
Application["IsRunning"] = false;
then:
private void MyMethod()
{
if (!((bool)Application["IsRunning"]))
{
Application["IsRunning"] = true;
// your code
}
}
Note that the state of a web application isn't always stable or intuitive. It's really meant to be a request/response system and is at the mercy of the web server for managing resources. This may not be as reliable as you expect.
You might want to consider having a separate application, such as a Windows Service, for performing ongoing background tasks.

Related

ViewModel event fires multiple times

I'm using MVVM Light for my application and I have also implemented the INavigationService for going back/for between pages.
So in a common scenario, it's like this
MainPage > Categories > Rounds > DataPage.
In the DataPage, I'm making a request to fetch the results and depending on the result returned from the callback I call the .GoBack() method to pop the current page from the stack and return to Rounds.
What I have noticed is that if I hit first the DataPage and the .GoBack() gets called and then tap on a different round the callback method will be fired twice, and if I go back and in again thrice, and continues like this.
Essentially this means that the .GoBack() will be called again and the navigation gets messed up.
I believe this has to do with not cleaning up the previous VM's, I tried changing this behavior with the UnRegister / Register class from SimpleIOC but no luck.
In the ViewModel class
public void UnsubscribeFromCallBack()
{
this.event -= method;
}
In the .xaml.cs page
protected override void OnDisappearing()
{
base.OnDisappearing();
PageViewModel vm = (this.BindingContext as PageViewModel);
vm.UnSubscribeFromCallback();
}

Async Page Asp.net webforms threads

I would like to solve a specific question I got, so this question is more likelly a discussion.
Basiclly, there is an asp.net project with a WebForm1.aspx, with a button on it. As soon as the clien press the button a thread is launch, and inmediatlly then, there is a Response.Redirect like this:
protected void Button1_Click(object sender, EventArgs e)
{
BL.Class1 cd = new BL.Class1();
cd.Run(); // or cd.AsyncRun();
Response.Redirect("~/WebForm2.aspx",true);
}
Of course evrything should be nonstatic. Bussiness Logic class looks somthing like this:
public class Class1
{
public int Signal = 0;
// non blocking Run... the webserver continues with this process running backwards
public void RunAsync()
{
Signal = 0;
new System.Threading.Thread(() =>
{
System.Threading.Thread.Sleep(100000); // simulate heavy task!
}
).Start();
Signal = 1;
}
// blocking Run...
public void Run()
{
Signal = 0;
System.Threading.Thread.Sleep(100000); // simulate heavy task!
Signal = 1;
}
}
With this in mind, here is the discussion:
- In WebForm2.aspx I would like to pool either from the client (javascript/ajax/nonstatic webservice) or the server to the client (registerscript with scriptmanager), in order to have the "Signal" variable set to "True" after the heavy process.. and tell the user (via a div with red background to green color) or something else.
- If so, how would be the best method if I do not want to use SignalR or Node.js or WebApi or WebSockets jet?
- Do you have any document, book where to explain such situation in an MVC project approach?
All communitty, really thanked on helping within this issue.
br,
Sounds like a simple meta refresh would do the trick, or a JavaScript that reloads the page on a set interval - no need for anything fancy if you don't want to.
Simply render the page (server-side) either with a red or a green div depending on the completion status of the heavy job.

The Application_PreRequestHandlerExecute event doesn't fire for PageMethods. What can I use instead?

This article explains that the PreRequestHandlerExecute event does not fire for PageMethod calls for whatever reason. However, I'm trying to use that event to populate the Principal object with the user's permissions so they can be checked within any web request (PageMethod call or not). I'm caching the permissions in the Session, so I need an event that fires whenever a PageMethod is called, and I need to have access to the Session. This way I can populate the Principal object with the security permissions cached in the session, and User.IsInRole() calls will work as expected. What event can I use?
You should implement an authorization module that will be run with every request that goes up to the server. This way you are able to authorize your principal for any request that come up to the server (page request, method, etc.)
public class AuthorizationModule : IHttpModule, IRequiresSessionState
{
//not going to implement it fully, might not compile
public void Init( HttpApplication context )
{
//you'll prolly want to hook up to the acquire request state event, but read up to make sure this is the one you want on the msdn
context.AcquireRequestState += AuthorizeRequest;
}
public void AuthorizeRequest( HttpContextBase httpContext )
{
// do you work in here
// you can redirect them wherever if they don't have permssion, log them out, etc
}
}
}
After you've crated the module, you'll need to hook it up in the web.config. Your type should include the namespace if it has one.
<httpModules>
<add name="AuthorizationModule" type="AuthorizationModule"/>
</httpModules>
I hope this helps.
You can use the Application_OnPostAuthenticateRequest as shown below (assuming you are using Forms Authentication. Else, pls replace the code with your Authentication mechanism):
public void Application_OnPostAuthenticateRequest(object sender, EventArgs e)
{
IPrincipal usr = HttpContext.Current.User;
if (usr.Identity.IsAuthenticated && usr.Identity.AuthenticationType == "Forms")
{
var fIdent = (FormsIdentity)usr.Identity;
var ci = new CustomIdentity(fIdent.Ticket);
var p = new CustomPrincipal(ci);
HttpContext.Current.User = p;
Thread.CurrentPrincipal = p;
}
}
Page Methods are static, and bypass the normal Page lifecycle, its objects and its events. The best you can do is pass authentication information as parameters to the Page Method itself.
From my point of view, you can:
1.- Use a common method you can call from every page method server code that have access to Session variables. Please refer to:
http://mattberseth.com/blog/2007/06/aspnet_ajax_use_pagemethods_pr.html
2.- Try to capture a similar behaviour later using __doPostBack() function to run server code. See if this work for you to capture page method async posbacks:
http://www.dotnetcurry.com/ShowArticle.aspx?ID=256
Hope that helps,

Why does my ASP.Net static function's "context" crossover between user sessions?

I think I need some help understanding how static objects persist in an ASP.Net application. I have this scenario:
someFile.cs in a class library:
public delegate void CustomFunction();
public static class A {
public static CustomFunction Func = null;
}
someOtherFile.cs in a class library:
public class Q {
public Q() {
if (A.Func != null) {
A.Func();
}
}
}
Some ASP.Net page:
Page_Init {
A.Func = MyFunc;
}
public void MyFunc() {
System.IO.File.AppendAllText(
"mydebug.txt", DateTime.Now.ToString("hh/mm/ss.fff", Session.SessionID));
}
Page_Load {
Q myQ = new Q();
System.Threading.Thread.Sleep(20000);
mQ = new Q();
}
The idea is that I have a business object which does some operation based on a callback function at the UI level. I set the callback function to a static variable on Page_Init (in the real code version, in the Master page, if that makes a difference). I thought that every execution of the page, no matter what user session it came from, would go through that function's logic but operate on its own set of data. What seems to be happening instead is a concurrency issue.
If I run one user session, then while it is sleeping between calls to that callback function, start another user session, when the first session comes back from sleeping it picks up the session ID from the second user session. How can this be possible?
Output of mydebug.txt:
01/01/01.000 abababababab (session #1, first call)
01/01/05.000 cdcdcdcdcdcd (session #2, first call - started 5 seconds after session #1)
01/01/21.000 cdcdcdcdcdcd (session #1 returns after the wait but has assumed the function context from session #2!!!!!)
01/01/25.000 cdcdcdcdcdcd (session #2 returns with its own context)
Why is the function's context (meaning, its local data, etc.) being overwritten from one user session to another?
Each request to an asp.net site comes in and is processed on it's own thread. But each of those threads belong to the same application. That means anything you mark as static is shared across all requests, and therefore also all sessions and users.
In this case, the MyFunc function that's part of your page class is copied over top of the static Func member in A with every page_init, and so every time any user does a page_init, he's replacing the A.Func used by all requests.
Static data is shared among the entire application domain of your webapp.
In short, it's shared among all the threads serving requests in your webapp, it's not bound to a session/thread/user in any way but to the webapp as a whole.(unlike e.g. php where each request lives in its own isolated environment bar a few knobs provided - such as the session variable.)
I won't try to improve on the other answers' explanations of static members, but do want to point out another way to code around your immediate problem.
As a solution, you could make an instance-oriented version of your class A, store it in a page-level variable, and pass it to Q's constructor on page load:
public class MyPage: Page {
private A2 _a2;
// I've modified A2's constructor here to accept the function
protected Page_Init() { this._a2 = new A2(MyFunc); }
protected Page_Load() {
Q myQ = new Q(this._a2);
// etc..
}
}
In fact, if there's no pressing need to declare A2 earlier, you could just instantiate it when you create your instance of Q in Page_Load.
Edit: to answer the question you raised in other comments, the reason the variables are being shared is that the requests are sharing the same delegate, which has only a single copy of its variables. See Jon Skeet's The Beauty of Closures for more details.
One solution you might consider is using [ThreadStatic].
http://msdn.microsoft.com/en-us/library/system.threadstaticattribute(VS.71).aspx
It will make your statics per thread. There are cavaets however so you should test.
If you want the data to persist only for the current request, use HttpContext.Items:
http://msdn.microsoft.com/en-us/library/system.web.httpcontext.items.aspx
If you want the data to persist for the current user's session (assuming you have session state enabled), use HttpContext.Session:
http://msdn.microsoft.com/en-us/library/system.web.httpcontext.session.aspx

How to add common code (specifically to methods marked WebMethod())

I have some ASP.NET page and webservice WebMethod() methods that I'd like to add some common code to. For example:
<WebMethod()> _
Public Function AddressLookup(ByVal zipCode As String) As Address
#If DEBUG Then
' Simulate a delay
System.Threading.Thread.Sleep(2000)
#End If
Return New Address()
End Function
I currently have the #If Debug code in all of my WebMethod() methods, but I am thinking there must be a better way to do this without having to actually type the code in.
Is there a way to determine if a request is to a WebMethod in Application_EndRequest so that I can add this delay project wide?
Note that some methods are Page methods and some are web service methods.
You can check the request URL in Application_EndRequest to determine whether it is a web method call. E.g. something like this (sorry it's in C#):
protected void Application_EndRequest(Object sender, EventArgs e)
{
if (Request.Url.ToString().IndexOf("MyWebService.asmx") > 0)
{
// Simulate a delay
System.Threading.Thread.Sleep(2000);
}
}
Encapsulate the #if DEBUG code in a method and mark it with <Conditional("DEBUG")>. This way, you just write a method call in each <WebMethod>. Might be useful.

Resources