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.
Related
I'm developing using DevExpress XAF, my problem is a little bit tricky, in short, when I save my class I make changes in other classes based on the data provided, I realized this with a controller that executes code when I close the detail view, the problem is that there is a scenario that does not meet my needs, here is it:
When I open a detail view already existing and that I modify some data, when I close the window, the program displays a window of confirmation ("do you want to register?) when I click on no, normally my view controller will not do anything because I refused to change my class data
Finally here is my question: How to test in my view controller if the object was registered or not before proceeding to the change and execute my code?
When you say register, I think you mean save.
You can use the ObjectSpace.GetObjectsToSave() method to obtain a list of objects which will be saved when ObjectSpace.CommitChanges() is called. You can then determine whether View.CurrentObject is in this list.
Alternatively you could use the ObjectSpace_ObjectChanged event. Something like this.
public class MyViewController : ObjectViewController<DetailView, Contact> {
protected override void OnActivated() {
base.OnActivated();
ObjectSpace.ObjectChanged += ObjectSpace_ObjectChanged;
}
void ObjectSpace_ObjectChanged(object sender, ObjectChangedEventArgs e) {
if (e.Object == View.CurrentObject) {
// execute your business logic
}
}
protected override void OnDeactivated() {
base.OnDeactivated();
ObjectSpace.ObjectChanged -= ObjectSpace_ObjectChanged;
}
}
See here for a Support Center discussion of a similar request.
I'm calling a number of methods that have been decorated with [WebMethod] via jQuery ajax.
These require a database connection to be set up in an external library that will be the same for each method.
My original code looked like this:
public partial class Server : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
// code to set up DB connections
ExternalLibrary.SetupDB();
}
[WebMethod]
public static string AjaxAccessibleMethod()
{
try
{
// get some data from the database via the external library
ExternalLibrary.CallDatabase();
}
catch(Exception ex)
{
// handle errors
}
}
}
This was working, but then started throwing exceptions claiming that the ExternalLibrary's database hadn't been initialized.
Placing breakpoints in my code I found that the Page_Load event wasn't being called when calling my AjaxAccessibleMethod, I also tried moving the DB setup stuff into the Page_Init event but likewise that wasn't called.
Can anyone explain to me the aspx page life cycle when using WebMethods? The fact that this worked initially seems to imply that Page_Load was called, but it no longer is.
Notice that the method you are using as WebMethod is static, this should be the first hint to the fact that Page object is not created at all.
Page Methods is a simple alternative to full blown web services, and as such, its life cycle is more similar to web service than to page. That is, request goes through the general ASP.NET pipeline, with objects like HttpContext, Request and such. But then the difference happens: for page requests and postbacks page object is created and the whole series of page events happens, whereas for page methods page object is not created, and method is simply called as Server.AjaxAccessibleMethod().
There is really no way to mix the two, because this would unnecessarily complicate processing of calls to page methods. So the only path forward for you here is duplicate necessary code:
protected void Page_Load(object sender, EventArgs e)
{
// code to set up DB connections
ExternalLibrary.SetupDB();
}
[WebMethod]
public static string AjaxAccessibleMethod()
{
ExternalLibrary.SetupDB();
...
}
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...
}
}
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.
I have over 30 aspx pages, i have discovered a problem recently that if i did any kind of database transaction like insert, update, delete and then after the transaction is complete i pressed F5 or refreshed the page in anyway the same is transaction occur.
I searched for a solution but all i could found is that i have to check for viewstate on each button which is impossible, cause that means there will be a lot of work. There got to be generic solution, please help me in this problem.
Edit:
Here is the code on one of the buttons which change a value in data base to either true or false:
protected void btn_Publish_Click(object sender, EventArgs e)
{
if (Convert.ToBoolean(int.Parse(hf_Published.Value.ToString())))
{
publish(false);
}
else
{
publish(true);
}
}
After the execution of the code if refreshed the page the same code is executed, i noticed that since a break point was placed on this method.
You can try this. I used this in several project and working successfully.
public bool IsRefreshed
{
get
{
if (Convert.ToString(Session["RefreshTimeStamp"]) == Convert.ToString(ViewState["RefreshTimeStamp"]))
{
Session["RefreshTimeStamp"] = HttpContext.Current.Server.UrlDecode(System.DateTime.Now.ToString());
return false;
}
else
{
return true;
}
}
}
protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
ViewState["RefreshTimeStamp"] = Session["RefreshTimeStamp"];
}
protected override void OnLoad(EventArgs e)
{
if (!Page.IsPostBack)
{
Session["RefreshTimeStamp"] = HttpContext.Current.Server.UrlDecode(System.DateTime.Now.ToString());
}
base.OnLoad(e);
}
There IS a generic solution, used for years by thousands of developers.
And the solution is: each time you perform an intrusive process at the server (insert/update/delete) you don't just render the page but rather you redirect the response with 302 to a fresh page with "your transaction succeeded" message.
This way, pressing the F5 will just refresh this message page, not the original page which triggers the transaction.
It is up to you whether or not this is directly applicable in your scenario.
http://en.wikipedia.org/wiki/Post/Redirect/Get
To fix this issue you could check the following:
Disable the submit button when necessary
Add some validation to your code and check for double entries
Redirect the user to another page after submit
Unless it's a real 'transaction' like payments etc. (which others already explained, do redirect etc.),
You could also try defining caching on your pages that interact with the Db or are bottlenecks for your app.
If you wanna have always live info (and it's that 'alive' type of app) then no luck with that solution (but even then), but usually, you can put some reasonable time expiration on how 'fresh' you want your data to be.
Caching ASP.NET Pages