I'm implementing an auto-refresh feature on a asp.net website.
The user does the login on the website, and if he goes to a specific page, which has a table that needs to be refreshed, a timer is created that refreshes the table.
But when the user logs out or the session expires, the timer keeps running. Now multiply this for X users, and we will have X timers running on the server.
What's the best way to get rid of the timers when they're no longer needed?
So far my code is the following:
protected static System.Timers.Timer _timer;
protected void Page_Load(object sender, EventArgs e)
{
...
ServiceStatus serv = new ServiceStatus();
OutSubscricoesInfoV2 subscr = new OutSubscricoesInfoV2();
serv = StreamerUtils.GetSubscricoesStreamer(ref subscr);
if (serv != null && serv.success)
{
StreamerUtils.StreamerState strState = StreamerUtils.GetStreamerState(subscr);
if (strState != null && strState.IsActive)
{
startAutoRefresh();
}
}
}
private void startAutoRefresh()
{
if (Session["RefreshTimer"] == null)
{
_timer = new System.Timers.Timer(10000);
_timer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
_timer.Enabled = true;
Session["RefreshTimer"] = _timer;
}
}
private static void OnTimedEvent(object source, ElapsedEventArgs e)
{
//TODO: call refresh function
}
In my page, i have the following button which the user can click to refresh the table:
<asp:ImageButton runat="server" ID="RefreshCot" OnClientClick="javascript:StocksListControl.TriggerPostBack(); return false;" CausesValidation="false" ImageUrl="/_layouts/images/refresh-title.png" />
I agree with the first comment to your question posted by Aristos, this is bad design.
For this situation I would suggest three options:
Use a asp.net Ajax control. An example can be found here: http://www.tutorialspoint.com/asp.net/asp.net_ajax_control.htm
AJAX poling - Have the timers in JavaScript which will sit on the clients. Once the timer has passed its elapsed time, the client will make an AJAX request to the server (preferably calling a web service) to fetch the updated data. I would recommend using a JavaScript library for this such as JQuery. The documentation on their ajax function is found here:
http://api.jquery.com/jQuery.ajax/
Consider using a library that provides real time functionality such as SignalR, here is a link to the libraries site:
http://signalr.net/
Now for the personal opinions; Of all 3 options, the 3rd will provide you with the most "elegant" solution.
The 1st option will require you to use asp.net AJAX controls, which produce ugly HTML and can be a pig to work with. Also, timers on the client will be created which remove the true "real-time" aspects.
The 2nd option will again put timers on the client, removing the true "real-time" aspects.
The 3rd option, will allow the server to be "aware" of connected clients, data shall be pushed to the clients, when available, via the use of "Hubs".
Whilst your'e at this learning curve crossroad, I would also recommend looking into some client side JavaScript design patterns to help structure your code on the clients. A great tool to use could be Knockout, found here:
http://knockoutjs.com/index.html
Here is a tutorial on how to use this with SignalR:
http://www.codeproject.com/Articles/322154/ASP-NET-MVC-SIngalR-and-Knockout-based-Real-time-U
The tutorial focuses on using ASP.NET MVC. I imagine this should be interchangeable with web forms, however, if the option is available to you I would recommend using MVC also.
Related
I have an aspx page to make calls to a web service, each of which can take up to few minutes and I want to make it work in a multi-threaded way. Basically what I want is when user clicks one of the buttons
I want to make a service call to my web service but I also want user to be able to click the other buttons and make other service calls if they want. and if the later calls
are completed faster than the first one, results must be shown to user without waiting for the result of the first call. (Yo can think about desktop sql editor applications)
However I can't manage this with my current method. The first call always blocks the following ones, I wonder If I can accomplish this
kind of behviour in a web application.
I use a code like the floowing for my service calls:
protected void GetResult_Click(object sender, EventArgs e)
{
ShowSelectData(sql, connStr, tabId);
}
private void ShowSelectData(string sql, string connStr, string tabId)
{
SqlServiceClient cli = new SqlServiceClient();
cli.ShowSelectDataCompleted += cli_ShowSelectDataCompleted;
cli.ShowSelectDataAsync(sql, connStr, tabId);
}
void cli_ShowSelectDataCompleted(object sender, SqlService.ShowSelectDataCompletedEventArgs e)
{
var res = e.Result;
//here I show resullts to user
}
I also add Async="true" to my aspx page
Basically what I want is when user clicks one of the buttons I want to
make a service call to my web service but I also want user to be able
to click the other buttons and make other service calls
What you asked can be accomplished by ajax async call; leave to your client the burden to call the service (by an async call) and manage the response.
When the user click a button make a call to the service; meantime the first call is executing the client can call the second, meantime first and second are executing the client can call the third... the user is not frozen waiting the first call to finish
If you can't call the service directly from a javascript client wrap server side the service calls into rest services and call the rest services from your client.
I'm currently using the "Session_Start" function within the Global.ascx file to save when an authenticated user visits my site.
This works OK if a users session expires, however as I'm using persistent cookies the user may return to the site within 28 days and this function will not be called and therefore will not be recording in the database that the user has visited.
I've taken a good look at all the functions available within Global.ascx, however I cannot find one that will perform what I need.
Application_Start - triggered only run within life cycle
Application_BeginRequest - each and every request made
Application_AuthenticateRequest - each and every request
Session_Start - when a new session is started
The two events that I believe could be used are Application_BeginRequest or Application_AuthenticateRequest.
Is there any way of limiting the above events to only run specific code on the first visit to a site and not on each request?
Alternatively is there any way of using my master file?
Any suggestions would be very useful.
Cheers
Why don't you implemented by your own? As you mentioned there is an event Application_BeginRequest. I think following might do the trick:
protected void Application_BeginRequest(object sender, EventArgs e)
{
string session_param_name = "SOME_SESSION_ID";
if (HttpContext.Current.Request.Form[session_param_name] == null)
{
//Count
}
else if (HttpContext.Current.Request.QueryString[session_param_name] == null)
{
//Also count
}
}
I am having a problem to design the best way for invoking a duplex WCF service from ASP.NET Application I have the following scenario:
1) I have a duplex WCF service with some operations
2) From an ASP.NET web application (which is my client) I make the default page implement the callback Interface and then call a method from the duplex service sending itself as the handler of the callback
3) When the callback returns on the default.aspx page I couldn't show the result on the page because the whole HttpContext is null so I can't access any control or Application[] or Session[] variables
Here is the code in the Default.aspx
[CallbackBehavior(UseSynchronizationContext = false)]
public partial class _Default : System.Web.UI.Page, VehicleTrackingService.IDuplexServiceCallback
{
public _Default()
{
}
protected void Page_Load(object sender, EventArgs e)
{
}
protected void Button1_Click(object sender, EventArgs e)
{
ThreadPool.QueueUserWorkItem(new WaitCallback(delegate
{
try
{
DuplexService client = new DuplexServiceClient(new InstanceContext(new_Default()));
switch (DropDownList1.SelectedItem.Value)
{
case "0":
{
client.Method1(int.Parse(txt_name.Text));
break;
}
case "1":
{
lbl_res.Text = "Not Provided yet.";
break;
}
default:
{
lbl_res.Text = "Not Provided yet.";
break;
}
}
}
catch(Exception ex)
{
}
}));
}
public void DuplexCallbackFunction(string response)
{
// Wanna to show result (the response) from here ...
}
Any Help Please?
You are calling the WCF service from the ASP.Net page while the page is being processed on the server.
The problem with this is that the page is on the server for a very short time, purhaps less than a second. Then the page has been returned to the browser before the WCF service has responded.
As Lloyd mentioned the way to fix this is to call the web service from your browser using AJAX.
For one example of how to do this see http://www.codeproject.com/Articles/128478/Consuming-WCF-REST-Services-Using-jQuery-AJAX-Call
You have to keep in mind that your application consists of a browser client that is accessing the ASP.NET application as a server, and these two communicate via HTTP requests and responses. Your ASP.NET application will most likely have sent an HTTP response back to the browser before the WCF service sends a message back to the ASP.NET application.
I think Shiraz and Lloyd have made an excellent suggestion; try to call the WCF service directly from the browser, if possible. This answer suggests that it may be possible to perform duplex communication with a WCF service with JavaScript.
However, there may be a number of reasons why you can't do that, such as credentials, network firewall rules, or simply the fact that the ASP.NET application has the necessary data to make the call to the WCF service, and perhaps you don't want to expose that data to the browser.
In these cases, you can choose to implement complicated solutions that involve using JavaScript in the browser to poll the ASP.NET server for updates. There are a couple of ways to do this. There is "short polling" and "long polling". There is also a relatively new feature called WebSockets, but whether or not your server and your target browser supports WebSockets is another question.
The MSDN documentation says:
HttpContext.RemapHandler Method - Enables you to specify a handler for the request.
I am trying to move the processing of the request from one handler to another depending on a condition in the first handler. The HttpContext.RemapHandler method seems to initialise an instance of the second handler but not call the HttpHandler.ProcessRequest method; the response is empty.
Does the HttpContext.RemapHandler method do what I think it should - transfer processing to a new HttpHandler and calling the HttpHandler.ProcessRequest method? Or should I be using another approach such as another method or an HttpModule?
EDIT:
Turns out I should be using a HTTPHandlerFactory. I have the solution working nicely now.
So what exactly is HttpContext.RemapHandler for?
You can use HttpContext.RemapHandler as you specified, however if another HttpHandler calls RemapHandler (e.g. ASP.NET MVC which registers MvcHandler in PostResolveRequestCache) your IHttpModule will never fire. This is maybe why IHttpHandler.Process was never called.
If this is your issue, you can simply define a route to ignore in MvcApplication.RegisterRoutes like this:
routes.IgnoreRoute("your_path/{*pathInfo}");
Also, remember that with Visual Studio Web Development Server and IIS6, RemapHandler will not work.
Here is an example of how to select the right way to remap the handler based on whether or not Integrated Pipeline is activated AND still be able to access the session:
public void Init(HttpApplication application)
{
if (HttpRuntime.UsingIntegratedPipeline)
// For IIS 7 and IIS 8
application.PostAuthorizeRequest += Application_PostAuthorizeRequest;
else
// For IIS 6
application.PostMapRequestHandler += Application_PostMapRequestHandler;
}
private void Application_PostAuthorizeRequest(object sender, EventArgs e)
{
((HttpApplication)sender).Context.RemapHandler(_myHandler);
}
private void Application_PostMapRequestHandler(object sender, EventArgs e)
{
((HttpApplication)sender).Context.Handler = _myHandler;
}
The difference between using a HttpHandlerFactory and HttpModule in this case is that the latter allows you to decide when to use which IHttpHandler regardless of ASP.NET IHttpHandler mappings. More on MSDN: HTTP Handlers and HTTP Modules Overview.
Okay.
So basically i am working on a message system on a webpage.
Users on my webpage is able to send each other messages, but now i want the messages to "pop up" on the receivers screen when sent. Exactly like when somebody on facebook sends you a message while your online, the message thing goes red. To solve my problem i need every client to know which other clients are online at the moment. I have solved this by coding an Observer-like pattern in my Global.asax:
public static void AddObserver(Observer o)
{
if(!observers.Contains(o))
observers.Add(o);
System.Diagnostics.Debug.WriteLine("Observer tilføjet : " + observers.Count);
}
public static void RemoveObserver(Observer o)
{
if (observers.Contains(o))
observers.Remove(o);
System.Diagnostics.Debug.WriteLine("Observer fjernet : " + observers.Count);
}
public static void NotifyObserversNewMail(Observer observer)
{
foreach (Observer o in observers)
if(!o.Equals(observer))
o.UpdateNewMail();
}
And the observer in this case i simply the Site.Master, which i have made extend the Observer class :
public partial class SiteMaster : System.Web.UI.MasterPage, Observer
{
protected void Page_Unload(object sender, EventArgs e)
{
Session["observer"] = this;
Global.AddObserver(this);
}
protected void Page_Load(object sender, EventArgs e)
{
//ADD OBSERVER TO GLOBAL.ASAX
if (Session["observer"] != null)
Global.RemoveObserver((Observer)Session["observer"]);
public void Update()
{
DLMessages.DataSource = ServiceMessages.GetInstance().GetMessages();
DLMessages.DataBind();
UPMessages.Update();
}
Where DLMessages is a DataList inside the UpdatePanel UPMessages.
So we have a "sender" client, and a "receiver" client.
When the sender creates a new message this method gets called:
protected void MessageSend(object source, EventArgs args)
{
Page.Validate("ValGroupMessageTo");
if (Page.IsValid)
{
ServiceMessages.GetInstance().SendMessage(ServiceCommunity.GetInstance().GetUser(MessageTo.Text).Id, ((User)Session["user"]).Id, MessageMessage.Text);
Global.NotifyObserversNewMail((Observer)Session["observer"]);
ClosePopups(new object(), new EventArgs());
Update();
}
}
As you can might notice it calls the Notify on global.asax, and the update() directly on itself. The UpdatePanel on the "sender" side updates perfectly, but on the receiver side nothing happens. Not in the UpdatePanel anyways.
Cause if i alter the code in the Update() to run through the messages from the DB, i can see that the message gets called fine, and the new message is loaded. Just not updated to the UpdatePanel.
So i have been thinking a lot about why the updatepanel doesnt get updated on the "receiver" side when the data gets updated, and my conclusion is it is because theres no partial postback on the "receiver" side. Yeah sure, the Update() method gets called, but theres no postback. So my question is this:
Is it possible to "force" a partial post back from the code-behind? Or is there another solution that might work better?
Hope it makes sense :-)
Do yourself a favour and build the whole thing using SignalR. It is a library for real time communication between the server and the browser for .NET (includes client-side libraries).
If you insist on doing it the hard way you should use a timer to trigger the update panel update
I'm not a big fan of working with updatepanels, but I think you can use the timer-control to force a partial postback.
Have a look at: http://mattberseth.com/blog/2007/08/using_the_ajax_timer_control_a.html
Those solutions, comet etc will work but really your best bet is to use socket.io
Real Time Browser Applications
You could also combined it with backbone.js and have a really nice app. I helped make a real time web messenger based on these 2.
I'm not an expert but you could try the Javascript/Jquery SetTimeout function associated with a WebService (.svc) to make periodic request from the client and retrieve data from the server.