If I need all the sessions, of all users on a website to reinitialize themselves, or perhaps all of them to go abandoned so that they will re-init themselves, how to go about this besides restarting the www service?
Many thanks!
You can't really do that using out of the box code.
One way I can think of is storing all Sessions in global context then iterate over this collection: add to the collection in Session_Start and remove in Session_End.
For example:
void Session_Start()
{
if (HttpContext.Current.Cache["Sessions"] == null)
HttpContext.Current.Cache["Sessions"] = new List<HttpSessionState>();
(HttpContext.Current.Cache["Sessions"] as List<HttpSessionState>).Add(HttpContext.Current.Session);
}
void Session_End()
{
if (HttpContext.Current.Cache["Sessions"] != null)
(HttpContext.Current.Cache["Sessions"] as List<HttpSessionState>).Remove(HttpContext.Current.Session);
}
I found a sort of a solution to this - rather than restarting the WWW service to achieve the reset of all sesssions result, you can just reycle the application poll from withing IIS Manager. Just faster, and does what i wanted it to do.
Sorry if this sounds trivial to some :)
Related
I'm using the new Universal Providers from Microsoft for session in SQL Server. The old implementation of session on SQL Server required a job (running every minute) to clear expired sessions. The new one does this check and clear on every request. Since I'm actually running in SQL Azure, I don't have SQL Agent to schedule jobs, so this sounds like a reasonable way to go about it (no, I don't want to pay for Azure Cache for session).
The problem is when multiple users access the site at the same time, they're both trying to clear the same expired sessions at the same time and the second gets an optimistic concurrency exception.
System.Data.OptimisticConcurrencyException: Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded. Refresh ObjectStateManager entries.
at System.Data.Mapping.Update.Internal.UpdateTranslator.Update(IEntityStateManager stateManager, IEntityAdapter adapter)
at System.Data.Objects.ObjectContext.SaveChanges(SaveOptions options)
at System.Web.Providers.DefaultSessionStateProvider.PurgeExpiredSessions()
at System.Web.Providers.DefaultSessionStateProvider.PurgeIfNeeded()
at System.Web.SessionState.SessionStateModule.BeginAcquireState(Object source, EventArgs e, AsyncCallback cb, Object extraData)
at System.Web.HttpApplication.AsyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)
I'm using ELMAH for error logging, and this is showing up with some frequency. Before I try to configure ELMAH to ignore the errors, does anyone know of a way to stop the errors from happening in the first place? Is there some configuration with the new providers that I'm missing?
Please download the newer version of the providers which can be found here: http://www.nuget.org/packages/System.Web.Providers. We have updated the way that we clean up expired sessions to run asynchronously and to handle error conditions. Please let us know if it does not correct your issues.
This package has a what I would describe as a bug. The premise of out of process session state is that multiple instances might be managing session state clean up. In this case all instances are running this method...
private void PurgeExpiredSessions()
{
using (SessionEntities entities = ModelHelper.CreateSessionEntities(this.ConnectionString))
{
foreach (SessionEntity entity in QueryHelper.GetExpiredSessions(entities))
{
entities.DeleteObject(entity);
}
entities.SaveChanges();
this.LastSessionPurgeTicks = DateTime.UtcNow.Ticks;
}
}
The problem is that one instance deletes the entities before the other(s) and entities throws the error described in the post. I asked the package authors to release the source code or fix this.. My untested text editor fix would be to add public virtual, so one could override the method or just change it too..
private void PurgeExpiredSessions()
{
using (SessionEntities entities = ModelHelper.CreateSessionEntities(this.ConnectionString))
{
var sqlCommand = #"DELETE dbo.Sessions WHERE Expires < GETUTCDATE()";
entities.ExecuteStoreCommand(sqlCommand);
this.LastSessionPurgeTicks = DateTime.UtcNow.Ticks;
}
}
The package authors are really fast with a response (answered while posting this!) and today they stated that they are working on releasing the code but that they might be able to just fix this. I requested an ETA and will try to follow up here if I get one.
Great package, it just needs a little maintenance.
Proper Answer: Wait for source code release or a fix update. Or De-compile and fix it yourself (If that is consistent with the license!)
*Update the package owners are considering fixing it this week. Yeah!
**Update.SOLVED!!! They evidently fixed it a while ago and I was installing the wrong package..
I was using http://nuget.org/packages/System.Web.Providers and I should have been using http://nuget.org/packages/Microsoft.AspNet.Providers/ .. It was not obvious to me which one was legacy and included in another package. They wrapped it in an empty catch..
private void PurgeExpiredSessions()
{
try
{
using (SessionEntities entities = ModelHelper.CreateSessionEntities(this.ConnectionString))
{
foreach (SessionEntity entity in QueryHelper.GetExpiredSessions(entities))
{
entities.DeleteObject(entity);
}
entities.SaveChanges();
this.LastSessionPurgeTicks = DateTime.UtcNow.Ticks;
}
}
catch
{
}
}
Thank you to the package team for such quick responses and great support!!!
I posted a question on this at the NuGet(http://www.nuget.org/packages/System.Web.Providers), and got a very quick response from the owners. After a bit of backwards and forwards, turns out they do have a fix for this, but is going out in the next update.
There was a suggestion here, that Microsoft isnt too keen on supporting this, but my experience has been otherwise, and have always received good support.
I've got quite a lot of code on my site that looks like this;
Item item;
if(Cache["foo"] != null)
{
item = (Item)Cache["foo"];
}
else
{
item = database.getItemFromDatabase();
Cache.insert(item, "foo", null, DateTime.Now.AddDays(1), ...
}
One such instance of this has a rather expensive getItemFromDatabase method (which is the main reason it's cached). The problem I have is that with every release or restart of the application, the cache is cleared and then an army of users come online and hit the above code, which kills our database server.
What is the typical method of dealing with these sorts of scenarios?
You could hook into the Application OnStart event in the global.asax file and call a method to load the expensive database calls in a seperate thread when the application starts.
It may also be an idea to use a specialised class for accessing these properties using a locking pattern to avoid multiple database calls when the initial value is null.
I want to know my website memory usage,first i want to know Session detail of all users,this will help me decide whether to change sessionState Mode to "SqlServer" or "StateServer".
How can i do?
Thanks
For website memory usage, I would look at perfmon. If I really wanted to count how much memory I was using in each user session, I would do that count when adding not when abandoning the session. This could be tricky if you've got Session["foo"]=bar all over the place, it needs to be wrapped up somehow.
If you do change to out of process session state, you will need to test everything that touches the session. Your session variables are crossing process boundaries, they need to be serializable and there are definitely some things that don't work.
I am not sure if this will help you solve the problem but you can try this piece of code in Session_End event... Assuming that this event is fired from your logout process..
This is the last of the events where Session Variable is available.
protected void Session_End(object sender, EventArgs e)
{
string strMessage = string.Empty;
for (int i = 0; i < this.Session.Count; i++)
{
strMessage += string.Format("Session of {0} Value is {1}", i.ToString(), this.Session[i].ToString());
strMessage += "/n";
}
}
this.Session.Count should give you the number of sessions in the server for the application. This solution may hold good only if your application is hosted in single web server and not on a web server farm. I am ignorant of how sessions are handled in a web server farm.
I have this code in the asp.net application start evert, and I'm not really familar with the Timer class but what I want to do is have one Trigger that goes off every night at 11 pm, one that goes off at 5:30 in the morning and then every hour after that.
private System.Threading.Timer timer;
protected void Application_Start(object sender, EventArgs e)
{
int intervalMilliseconds = 60 * 1000;
timer = new System.Threading.Timer(new System.Threading.TimerCallback(TimedEvent), null, intervalMilliseconds, intervalMilliseconds);
}
protected void Application_End(object sender, EventArgs e)
{
if (timer != null) timer.Dispose();
}
private void TimedEvent(object stateInfo)
{
MyClass.ExecuteCode();
}
*Please no answers in the way of "don't use asp.net to do triggers because of the lifecycle".
*Again - please no posts on what not to use. I've received two post both telling me what not to use and both not related to my question which is about the Timer class and how to use it.
From your question i'm assuming you don't have full control over your hosting environment, so will try to avoid the schedule it... etc answers.
Having said that, you still need to be aware of the asp.net lifecycle, and your trigger approach is fraught with dangers.
Do you get enough traffic that the application won't end unexpectedly? Do you know the configuration of IIS, so recycling is not a worry?
I can see three approaches:
I would recommend having a page, which uses some sort of key, which is only known
by the caller. Have this page triggered by a watchmouse (See: http://www.watchmouse.com/en/), or scheduled crawler on a pc/server which will always be on, at the times you need it to be triggered.
An alternative would be to trigger a database process, which runs when needed to.
Depending on your environment, this can be scheduled too.
Another would be to check a log file, on users accessing the page, and if it is the first access within the hour, trigger your process. (Do this for whatever period you need.)
However this depends entirely on how heavily your site is accessed, and may not work reliably.
When you create your timer and hook up its tick/elapsed event, set the interval to be every 5 minutes or so.
Then in the tick/elapsed event handler, check the current time and perform an action where necessary. Obviously you will also need to record when an actino has been performed so you don't perform it at 10:58 and 11:03 pm.
Have a look at Quartz.NET, which will allow you to set up cron-like triggers.
Maybe a different way of doing what you want: Instead of relying on ASP to be active, perhaps you can just use the windows scheduler to schedule your event. It has more of the scheduling features you want and will be likely be more reliable as well as already debugged. Your timed event can be as simple as accessing http://localhost/YourApp/.aspx. You'll get the same effect with the added benefit that if your app happens to have recycled, your event will still execute as the 1st request.
You can do the kind of thing you're describing by using the inbuilt ASP.NET Cache.Add CacheItemRemovedCallback delegate. It's a bit of a roundabout way of using it, but you can do effective scheduling this way.
There's an article here showing how to do it.
More information on the CacheItemRemovedCallback here.
Edit: I know you said no services, but if you check the server and find you can use Scheduled Tasks, you can use that to run a console app on a specific schedule like some other other answers mention.
We are trying to lighten our page load as much as possible. Since ViewState can sometimes swell up to 100k of the page, I'd love to completely eliminate it.
I'd love to hear some techniques other people have used to move ViewState to a custom provider.
That said, a few caveats:
We serve on average 2 Million unique visitors per hour.
Because of this, Database reads have been a serious issue in performance, so I don't want to store ViewState in the database.
We also are behind a load balancer, so any solution has to work with the user bouncing from machine to machine per postback.
Ideas?
How do you handle Session State? There is a built-in "store the viewstate in the session state" provider. If you are storing the session state in some fast, out of proc system, that might be the best option for the viewstate.
edit: to do this add the following code to the your Page classes / global page base class
protected override PageStatePersister PageStatePersister {
get { return new SessionPageStatePersister(this); }
}
Also... this is by no means a perfect (or even good) solution to a large viewstate. As always, minimize the size of the viewstate as much as possible. However, the SessionPageStatePersister is relatively intelligent and avoids storing an unbounded number of viewstates per session as well as avoids storing only a single viewstate per session.
I have tested many ways to remove the load of view state from the page and between all hacks and some software out there the only thing that it is truly scalable is the StrangeLoops As10000 appliance. Transparent, no need to change the underlying application.
As previously stated, I have used the database to store the ViewState in the past. Although this works for us, we don't come close to 2 million unique visitors per hour.
I think a hardware solution is definitely the way to go, whether using the StrangeLoop products or another product.
The following works quite well for me:
string vsid;
protected override object LoadPageStateFromPersistenceMedium()
{
Pair vs = base.LoadPageStateFromPersistenceMedium() as Pair;
vsid = vs.First as string;
object result = Session[vsid];
Session.Remove(vsid);
return result;
}
protected override void SavePageStateToPersistenceMedium(object state)
{
if (vsid == null)
{
vsid = Guid.NewGuid().ToString();
}
Session[vsid] = state;
base.SavePageStateToPersistenceMedium(new Pair(vsid, null));
}
You can always compress ViewState so you get the benefits of ViewState without so much bloat:
public partial class _Default : System.Web.UI.Page {
protected override object LoadPageStateFromPersistenceMedium() {
string viewState = Request.Form["__VSTATE"];
byte[] bytes = Convert.FromBase64String(viewState);
bytes = Compressor.Decompress(bytes);
LosFormatter formatter = new LosFormatter();
return formatter.Deserialize(Convert.ToBase64String(bytes));
}
protected override void SavePageStateToPersistenceMedium(object viewState) {
LosFormatter formatter = new LosFormatter();
StringWriter writer = new StringWriter();
formatter.Serialize(writer, viewState);
string viewStateString = writer.ToString();
byte[] bytes = Convert.FromBase64String(viewStateString);
bytes = Compressor.Compress(bytes);
ClientScript.RegisterHiddenField("__VSTATE", Convert.ToBase64String(bytes));
}
// ...
}
using System.IO;
using System.IO.Compression;
public static class Compressor {
public static byte[] Compress(byte[] data) {
MemoryStream output = new MemoryStream();
GZipStream gzip = new GZipStream(output,
CompressionMode.Compress, true);
gzip.Write(data, 0, data.Length);
gzip.Close();
return output.ToArray();
}
public static byte[] Decompress(byte[] data) {
MemoryStream input = new MemoryStream();
input.Write(data, 0, data.Length);
input.Position = 0;
GZipStream gzip = new GZipStream(input,
CompressionMode.Decompress, true);
MemoryStream output = new MemoryStream();
byte[] buff = new byte[64];
int read = -1;
read = gzip.Read(buff, 0, buff.Length);
while(read > 0) {
output.Write(buff, 0, read);
read = gzip.Read(buff, 0, buff.Length);
}
gzip.Close();
return output.ToArray();
}
}
Due to the typical organizational bloat, requesting new hardware takes eons, and requesting hardware that would involve a complete rewire of our current setup would probably get some severe resistance from the engineering department.
I really need to come up with a software solution, because that's the only world I have some control over.
Yay for Enterprise :(
I've tried to find some of the products I had researched in the past that works just like StrangeLoops (but software based) It looks like they went all out of business, the only thing from my list that still up there is ScaleOut but they are specialized in session state caching.
I understand how hard it is to sell hardware solutions to senior management but it is always a good idea to at least get management to accept listening to the hardware's sales rep. I am much rather putting some hardware that will present me with an immediate solution because it allows me (or buy me some time) to get some other real job done.
I understand, it really sucks but the alternative is to change your code for optimization and that would maybe cost a lot more than getting an appliance.
Let me know if you find another software based solution.
I'm going to see if I can come up with a way to leverage our current State server to contain the viewstate in memory, I should be able to use the user session ID to keep things synched up between machines.
If I come up with a good solution, I'll remove any IP protected code and put it out for public use.
Oh no, red tape. Well this is going to be a tall order to fill. You mentioned here that you use a state server to serve your session state. How do you have this setup? Maybe you can do something similar here also?
Edit
Awh #Jonathan, you posted while I was typing this answer up. I think going that route could be promising. One thing is that it will definitely be memory intensive.
#Mike I don't think storing it in the session information will be a good idea, due to the memory intensiveness of viewstate and also how many times you will need to access the viewstate. SessionState is accessed a lot less often as the viewstate. I would keep the two separate.
I think the ultimate solution would be storing the ViewState on the client some how and maybe worth looking at. With Google Gears, this could be possible now.
Have you considered if you really need all that viewstate? For example, if you populate a datagrid from a database, all the data will be saved in viewstate by default. However, if the grid is just for presenting data, you dont need a form a all, and hence no viewstate.
You only need viewstate when there is some interaction with the user through postbacks, and even then the actual form data may be sufficient to recreate the view. You can selectively disable viewstate for controls on the page.
You have a very special UI if you actually need 100K of viewstate. If you reduce the viewstate to what is absolutely necessary, it might turn out to be the easiest and most scalable to keep the viewstate in the page.
I might have a simple solution for you in another post. It's a simple class to include in your app and a few lines of code in the asp.net page itself. If you combine it with a distributed caching system you could save a lot of dough as viewstate is large and costly. Microsoft’s velocity might be a good product to attach this method too. If you do use it and save a ton of money though I'd love a little mention for that. Also if you are unsure of anything let me know and I can talk with you in person.
Here is the link to my code. link text
If you are concerned with scaling then using the session token as a unique identifier or storing the state in session is more or less guaranteed to work in a web farm scenario.
Store the viewstate in a session object and use a distributed cache or state service to store session seperate from the we servers such as microsofts velocity.
I know this is a little stale, but I've been working for a couple of days on an opensource "virtual appliance" using squid and ecap to:
1.) gzip
2.) handle ssl
3.) replace viewstate with a token on request / response
4.) memcache for object caching
Anyways, it looks pretty promising. basically it would sit in front of the loadbalancers and should really help client performance. Doesnt seem to be very hard to set up either.
I blogged on this a while ago - the solution is at http://www.adverseconditionals.com/2008/06/storing-viewstate-in-memcached-ultimate.html
This lets you change the ViewState provider to one of your choice without having to change each of your Page classes, by using a custom PageAdapter. I stored the ViewState in memcached. In retrospect I think storing it in a database or on disk is better - we filled memcached up very quickly. Its a very low friction solution.
No need to buy or sell anything to eliminate viewstate bloating. Just need to extend the HiddenFieldPageStatePersister. The 100-200KB of ViewState will stay on the server and will send only a 62byte token on the page instead.
Here is a detailed article on how this can be done:
http://ashishnangla.com/2011/07/21/reducing-size-of-viewstate-in-asp-net-webforms-by-writing-a-custom-viewstate-provider-pagestatepersister-part-12/