Showing posts with label updates. Show all posts
Showing posts with label updates. Show all posts

Wednesday, March 28, 2012

updates from another thread

Hi, I'm trying to get a label control to update with dynamic information when a timer does its tick event.

I can get it to update with information hard-coded into the tick event, but i can't seem to get any data from a global variable or other shared resource.

Here's what i have so far-

using System;using System.Data;using System.Configuration;using System.Web;using System.Web.Security;using System.Web.UI;using System.Web.UI.WebControls;using System.Web.UI.WebControls.WebParts;using System.Web.UI.HtmlControls;using System.Threading;public partialclass _Default : System.Web.UI.Page {string temp;protected void Page_Load(object sender, EventArgs e) { }protected void Timer1_Tick(object sender, EventArgs e) { Label1.Text ="Tick at " + DateTime.Now.ToString()+"<br />";if (temp !=null) Label1.Text +="register at-"+temp; }protected void Button1_Click(object sender, EventArgs e) { Thread a =new Thread(Foo); a.Start(); }protected void Foo() {while (true) { Thread.Sleep(100); temp = DateTime.Now.Day.ToString(); } }}

(that's actually a +"<br />" at the end of the first line on the tick event)

and the markup-

<%@dotnet.itags.org. Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head runat="server"> <title>Untitled Page</title></head><body> <form id="form1" runat="server"> <asp:ScriptManager ID="ScriptManager1" runat="server" /> <div> <asp:UpdatePanel ID="UpdatePanel1" runat="server" UpdateMode="Conditional"> <ContentTemplate> <asp:Label ID="Label1" runat="server" Text="Label"></asp:Label> </ContentTemplate> <Triggers> <asp:AsyncPostBackTrigger ControlID="Timer1" EventName="Tick" /> </Triggers> </asp:UpdatePanel> </div> <asp:Timer ID="Timer1" runat="server" Interval="500" OnTick="Timer1_Tick"> </asp:Timer> <asp:Button ID="Button1" runat="server" OnClick="Button1_Click" Text="Button" /> </form> </body></html>
the 'register at" text never fires. I've tried using Session and Cache variables in place of a global string but no luck.

I am not sure how it is not working when puting it in Session/Cache, would you mind posting the code?


Here's the code using session-

using System;using System.Data;using System.Configuration;using System.Web;using System.Web.Security;using System.Web.UI;using System.Web.UI.WebControls;using System.Web.UI.WebControls.WebParts;using System.Web.UI.HtmlControls;using System.Threading;public partialclass _Default : System.Web.UI.Page {protected void Page_Load(object sender, EventArgs e) {if (!IsPostBack) Session["Store"] =null; }protected void Timer1_Tick(object sender, EventArgs e) { Label1.Text ="Tick at " + DateTime.Now.ToString()+"<br />";if (Session["Store"] !=null) Label1.Text +="register at-" + Session["Store"].ToString(); }protected void Button1_Click(object sender, EventArgs e) { Thread a =new Thread(Foo); a.Start(); }protected void Foo() {while (true) { Thread.Sleep(100); Session["Store"] = DateTime.Now.ToString(); } }}

It is not possible to access the session/request/response/cache from an different thread, also creating thread/using threadpool is not an good practise.


How should I update the label control then?

Or if using another thread is not good practice, i don't see how i'm going to be able to get the button postback to finish so i can update the label cleint side from the server during a (partial) postback


I am still not clear about your requirment, anyway here is the code snippet which will allow you to access the session from a different thread:

protected void Button1_Click(object sender, EventArgs e){ ThreadPool.QueueUserWorkItem(new WaitCallback(foo), Session);}private void foo(object state){ HttpSessionState session = (HttpSessionState)state; session["Store"] = DateTime.Now.ToString();}

Initial tests with this method provide the functionality I was after. I'll try to implament it today and let you know how it goes.


Indeed this seems to work well. I have 2 follow up questions relating to it though-

1. I went ahead and passed the session variable to other functions I use by reference...I'm guessing this is ok?

eg-

protected void Button1_Click(object sender, EventArgs e) { ThreadPool.QueueUserWorkItem(new WaitCallback(foo), Session); }private void foo(object state) { HttpSessionState session = (HttpSessionState)state; Thread.Sleep(100); session["Store"] = DateTime.Now.ToString(); Thread.Sleep(1000); foo2(ref session); }private void foo2(ref HttpSessionState session) { session["Store"] = DateTime.Now.ToString(); }

2. I notcied the application context still stays around after the browser is closed(presumably waiting for the thread to end?) should I manually be stopping the proccess somehow?


1. Yes you can pass it from the worker thread method.
2. The Thread returns to threadpool as soon as the foo2 method completes, no do not have to do anything.

Since it solved your problem, dont forget to mark it as answer.


Let's take another stab at this. You didn't really state the object of what you were trying to achieve. Why are you trying to use the variable temp? And if it truly is a shared variable, why didn't you just make it static? A Session variable certainly isn't global to the application. There's got to be a reason you're doing this and perhaps there is a much better approach.


The end result alows me to provided feekback to the cleint about a job currently being ran on the server (in psudo-real time). The timer updates the label on the client but it needs to be able to read from a variable (or somthing) that the job running on the server can write to. The session variable only needs to be global to the session (mutliple people could be using this at a time).

If there is another way to do this without using the cache or session I'd prefer too, but I havn't seen a way to do this yet...


Well there are certainly more expensive techniques such as using a Windows Service to host the job and querying it. Or using a DB entry to write the job status and querying it with a web service.

However you might be interested in this person's approach. He used a Cache object, but there is no reason it couldn't be Session (but Cache can be used if a unique identifier is set for a collection of jobs). The main difference is that his whole task is in this object, and it's public properties can be used to get it's status.

http://www.eggheadcafe.com/articles/20051223.asp


Use the Cache/ Store the Jobs status in DB as muliple user will be able to see the same result. BTW for one User you cannot use the session for storing the long running task status as the session access is always sequential.


I did try using the cache and i wasn't abe to get it to work ( see the first post). Essesntially the source looks the same as the session example except you use cache['whatever'] instead of session["whatever"].

I was under the impression that the session[] object was unique for each 'cleint session' that is, each cleint request would have it's own session object to work with. If this is the case why can't i use it for multiple users

@.wrayx1- I wanted to stay away from using a service althogh I have read some thing about how to get them to work, i think it overcompliactes the simple job I'm trying to do.

updates, both session and deserialisation

hi,

I'm new to the forum and Asp.net ajax but have been a c# dev for a while. My question is regarding using the session from within Ajax, and also to boot reading in a file.

the following pseudocode outlines my problem, the button and label are both in update panel. which itself is working fine (as on the 2nd click the session variable is shown)

basically,

button1 click set session["test"] = hello;

in the page load event have

if(session != null) label1 = session[hello];

what gets me is why when clicking a link (still within the update panel) the session variable is shown, but not through the original request. As I thought the entire page cycle is processed at the server and only the items in the update panel (in this case update mode is always) are refreshed?

the same happens with deserialization when used from the wizard in an update panel, it loads up the previous file rather than the new one but i imagine its somthing I have done wrong...

I have a quick fix with a timer set to 1second and calling my refresh function. I've also looked at using the Ajax profile for storing data i would else have stored in the session.

I was just wondering if anybody could point out my mistake or offer any alternatives. (using the membership and roles isnt feasable on this project unfortunatly)

well cheers and im sure it must be just somthing i have missed!

initiagroup:

As I thought the entire page cycle is processed at the server and only the items in the update panel (in this case update mode is always) are refreshed?

That's correct.

Your problem sounds like it almost has to be a page life cycle issue. Can you post a little bit more code?


thanks for your quick reply. Here is an extremly simple code snippit that shows my problem... its ok i think i have worked it out. Am i right in thinking that even without the update panel that code wouldnt work?

1<%@. Page Language="C#" AutoEventWireup="true" CodeFile="test.aspx.cs" Inherits="test" %>23<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">45<html xmlns="http://www.w3.org/1999/xhtml" >6<head runat="server">7 <title>Untitled Page</title>8</head>9<body>10 <form id="form1" runat="server">11 <asp:ScriptManager ID="ScriptManager1" runat="server">12 </asp:ScriptManager>13 <div>14 <asp:UpdatePanel ID="upd1" runat="server">15 <ContentTemplate>16 <asp:label ID="lbl1" runat="server"></asp:label>17 <asp:Button ID="btn1" runat="server" Text="click" OnClick="btn1_Click" />18 </ContentTemplate>19 </asp:UpdatePanel>20 </div>21 </form>22</body>23</html>

and the code behind

1using System;2using System.Data;3using System.Configuration;4using System.Collections;5using System.Web;6using System.Web.Security;7using System.Web.UI;8using System.Web.UI.WebControls;9using System.Web.UI.WebControls.WebParts;10using System.Web.UI.HtmlControls;1112public partialclass test : System.Web.UI.Page13{14protected void Page_Load(object sender, EventArgs e)15 {16if (Session["test"] !=null)17 {18 lbl1.Text = Session["test"].ToString();19 }20 }21protected void btn1_Click(object sender, EventArgs e)22 {23 Session["test"] ="test";24 }25}26

as you see very easy just click the button and see what happens. In debug it hits the page load event after the button is pressed.

oh and its just a standard ajax template from the new website dialog box.

Cheers.

Monday, March 26, 2012

Updating the user interface on a web form BEFORE UpdatePanel finishes

Hello

does anyone know if it is possible to dynamically alter the contents of a control (e.g. a label) so that it updates BEFORE the UpdatePanel finishes its asynchronous operation? An example might be for a progress bar. I have a process which takes up to 5 minutes, but which generates an event as it progresses. I want to update a control each time this event gets triggered, but because I update the user interface in the async part, it doesnt do anything until it has completed.

For example imagine I have a button with an OnClick event inside an UpdatePanel, alongside a label in the UpdatePanel.
WHen I click the button, if I loop through one hundred objects, andwish to update the contents of the label as I do this (i.e. 'On itemnumber: x'), how is this done?

Thanks

Tom.

Have you tried calling the .Update() method on your update panel in the loop? That may or may not work.


Take a look at this:http://encosia.com/2007/10/03/easy-incremental-status-updates-for-long-requests/


I did try this within the asyn call, but nothing happens. I am assuming that whatever happens is built into a long string of javascript or suchlike which is not executed until completion.

That's right. Output buffering prevents anything along those lines from working. Using an iframe lets you work more interactively.