I have a large ASP.NET/C# application that we're currently expanding on. I need to add a querystring parameter to a page and have that parameter be added automatically to every request thereafter.
For example, let's say the user chooses mode=1. I need to add &mode=1 to the querystring of every single link that is clicked from that point forward. At any point, the user can change the mode=2. So then I need that change to be reflected on each subsequent request.
And yes, I realize that what I'm basically looking for is to store a flag in either a session variable or a cookie. However, we've done that and we're having issues with it not persisting correctly. If nothing else, I'd like to put this in the querystring if only for testing purposes to see if the issue is simply with session/cookie state, or if somewhere in our code it's getting improperly reset.
I would personally try and rework this approach as it sounds messy and it likely to cause issues down the track - sessions are perfect for this type of thing.
If you really need to do this I would suggest writing up a http handler to intercept all http requests and make sure these parameters are in included in each request
See http://support.microsoft.com/kb/308001
Related
I'm making a simple asp.net app that displays data which can be filtered based on a few different parameters. As such, the different filters that are currently selected need to be saved somewhere. I'm fairly new to .NET, and am wondering the best way to save this information. I noticed a coworker used Request.QueryString in conjunction with the Sessions dictionary. Something like this on page load:
protected void Page_Load(object sender, EventArgs e)
{
if (Request.QueryString["Category"] != null &&
Request.QueryString["Value"] != null)
{
string Category = Request.QueryString["Category"];
string CategoryValue = Request.QueryString["Value"];
// selectedFacets is the server side dictionary
selectedFacets.Add(Category, CategoryValue);
}
}
The QueryString here is changed when the user presses a button on the webpage, updating the URL.
My question is why even bother with the QueryString at all when all we're using it for is saving a value server side anyway? Wouldn't just making the button an asp controller be easier, something like:
protected void exampleCatexampleVal_Button_onClick(object sender, EventArgs e)
{
selectedFacets.Add(exampleCat, exampleVal);
}
Similar business goes on the with the Sessions dictionary: it's just used to save a bunch of values to variables on the server, so why use it in the first place? I'm sure there's a good reason, but right now they just seems overly complicated for what they do. Thank you!
Based on your code examples, I understand that you're talking about ASP.NET WebForms.
Your use case is not complete, but I'll show here some alternatives to achieve your goal. If you give further information, I'll gladly update my answer.
Before we get to it, let me just put things clear: HTTP is stateless. Understanding this basic rule is very important. It means that your server will receive a request, send it to your app (and the .NET process), get the resulting page (and assets) and send it back to the client (mostly, a browser). End of story.
(Almost) Everything that you've created to respond to the request will be lost. And that's why we have options on where to store objects/values across requests.
Server-side Session
This is one of the easiest options. You simply call this.Session.Add("key", object) and it's done. Let's dig into it:
It will use server resources. That is, the most you use the session, the most memory (and other resources, as needed) your app will consume.
It will be harder to scale, because data will be on your server memory. Vertical scale may be an option, according to your hardware, but horizontal scale will be limited. You can use a session-server or store session on a SQL Server database, but it won't be so efficient anymore.
It's attached to your client session. It will be lost if the user opens another browser or sends a link to his friend.
It's relatively safe. I say relatively because of the options below. At least it's server side.
GET arguments (AKA QueryString)
That's another option, and you know it already. You can send data back and forth using the querystring (?that=stuff&on=the&URL=youKnow).
It's limited to 2000 characters and that must be serializable. That's why you probably won't put a DataGrid there.
The user may change it. Be aware! Always sanitize data from the QueryString.
User is free to bookmark the link or send it to a friend and stuff will be the same. That's nice, mind you.
ViewState
You may have heard about it, it's the engine that makes WebForms so lovely (and so hateful). By default, each controller on your page will have its state serialized to the viewstate, which is a huge hidden field with encrypted data on your page. Go on, click "View source" and look for it. Don't scream, please. You may add arbitrary data to the ViewState just like the Session.
It's on the client side. Don't trust it.
It will be send back and forth on each request, so it will consume extra bandwidth.
It will take time to be deserialized/serialized on each request/response.
Data must be serializable (you know what I mean).
So, by now I hope that you have enough information to make your own decision.
If I missed anything, please let me know.
Have a look at this MSDN Article first. I read through it, and it may answer your question for you.
http://msdn.microsoft.com/en-us/magazine/cc300437.aspx
What you're missing, is how the asp.net page lifecycle works:
http://msdn.microsoft.com/en-us/library/ms178472(v=vs.100).aspx
The thing is, that 'server variable' won't persist between postbacks (AFAIK). It's only useful inside that page, right then. As soon as the page is disposed at the end of the cycle, that dictionary is gone. So you have to store it somewhere if you want to use it later. The article I referenced shows you all the places that you can store information to persist it and where you store it depends on how long you need it to persist, and how many users should have access to it.
Now, certainly, if you DON'T want to persist that dictionary, then sure, just store it the page variable. That's just fine. There's no reason to persist data that you never need again.
It's always good to keep in mind that there is a slight performance hit when storing and retrieving session state from database or from separate process service (StateServer). If session state is stored in-memory, you cannot scale your application to a web farm and this wastes valueable memory in the web server.
On the other hand, using query string values won't waste your memory and resources, it is fast and you don't have to think about managing session state. It gives SEO benefit and allows bookmarks/favorites.
However, you can store only limited amount of data using query string (WWW FAQs: What is the maximum length of a URL). It can also pose a security risk, if sensitive data is exposed or a malicious user tries to find a bug in your code that mishandles URL values. SQL injection attack is one scenario. What you can do is encrypt sensitive values.
Overall there are many aspects to consider here.
One of the benefits of using query string values is if you need bookmarks/favorites stored in your application that would allow a user to directly navigate to a page and have certain values be passed into the page without the assistance of an in-memory cache. Take the following for example:
I have a product page that displays a grid view of products that can be filtered by a category name. If I use the categoryId value in the query string, then I can make a bookmark to this page and then later click on the bookmark and the page will work as I left it earlier. Depending upon in-memory cache, that may or may not be there, would not guarantee that my bookmark would work every time.
I have in the past always had quite a few problems maintaining the session state with WebMatrix, and handling them when expecting them to be timed-out (mainly because I am still learning).
The user input must always be remembered, because if they submit and a custom error occurs, I don't want them to have to re-input all of the information back into the form.
I think I have a method figured out (finally) that can properly maintain and manage timed-out session variables in the future, when they are needed.
I realize that there are several other methods of transferring data between web pages, and believe me, when applicable, they will certainly be used first. This question only pertains to when I feel like the session variable is my best option.
My problem is, I always think I have it figured out, and then, only after I have set up over half of the coding, do I realize why it doesn't quite work, and then find some sloppy (but effective) work around that will at least work for that project.
The projects I will use session variables in use the common database with web interface combination. Usually there are 3 main pages: an add entry page, an edit entry page, and a lookup entry page. The add entry page and the lookup entry page eventually post and redirect to the edit entry page.
Before I begin my next project, I thought it would be wise to inquire if my method is at least aiming in the right direction, or if I am still not approaching this quite right.
Here is what I think might work (although, it seems a bit too easy):
Use local variables per page.
In an (IsPost) branch assign the session variables based off of the local variables just before posting/redirecting.
On the other page, just after being redirected, use the session variables to assign new static local variables.
In other words: I will (when necessary) use the session variables only to transfer the data which will happen in a completely acceptable amount of time (not allowing the session state enough time to timeout), and then referring only to the local variables when needed, per page.
Am I crazy or is this the best way (or at least a decently viable way) to handle this, when forced to work with the session state in WebMatrix?
Sorry if this is a stupid question xD
In my opinion, you should not use Session variables to remember what the user entered into the form. The form - add or edit - should post to itself for validation. That way, the values are available in the Request.Form collection. You can easily repopulate the form in the event of a validation error. On successful submission, you insert or update the database, and then redirect to another page to prevent duplicate submission.
Session variables are really easy to use if used appropriately. I suspect your difficulties arise because you are using them for the wrong scenarios.
Is there an easier way to prevent a duplicate insert after refresh? The way I do it now is to select everything with the all fields except ID as parameters; if a record exists i don't insert. Is there a way to possible detect refresh?
Assuming it's a database, you could put a unique constraint on the combination of "all fields except ID" and catch the exception on an insert or update.
I agree with #Austin Salonen that you should start by protecting the DB with primary keys, unique constraints and foreign keys.
That done, many websites will include some JS behind submit buttons to disable the button immediately before sending on the request. This way, users who double click don't send two requests.
I think you may want to the EXISTS function.
Here's a simple explanation of EXISTS I found through google.
Like Dereleased said, use a 303-based redirect. Make the form submission use POST and then after saving have it send a 303 header and send them to the post-submit URL via a Location header which will be fetched via GET and a refresh will not be re-posting data.
It has been a long time since I have done any real web work. But back in the 1.1 days I remember using ids associated with a postback to determine if a refresh had occured.
After a quick search I think this is the article I based my solution from:
http://msdn.microsoft.com/en-us/library/ms379557(VS.80).aspx
It basically shows you how to build a new page class that you can inherit from. The base class will expose a method that you call when you are doing something that shouldn't be repeated on a refresh, and an IsPageRefresh method to track if a refresh has occured.
That article was the basis for alot of variations with similar goals, so it should be a good place to start. Unfortunately I can't remember enough about how it went to really give any more help.
I second the option to redirect a user to another (confirmation) page after the request has been submitted (a record inserted into the database). That way they will not be able to do a refresh.
You could also have a flag that indicates whether the insert request has been submitted and store it either on the page (with javascript) or in the session. You could also go further and store it somewhere else but that's an architectural decision on the part of your web application.
If you're using an AJAX request to insert a record then it's a bit harder to prevent this on the client side.
I'd rather do an indicator/flag then compare the fields. This, of course, depends on your records. For example, if it is a simple shop and the user wants to make an identical order then you will treat it as a duplicate order and effectively prevent the functionality.
What DB are you using? If it's MySQL, and certain other factors of your implementation align, you could always use INSERT IGNORE INTO .... EDIT: Struck for SQL Server
Alternatively, you could create "handler" pages, e.g. your process looks like this:
User attempts to perform "action"
User is sent to "doAction.xxx"
"doAction.xxx" completes, and redirects to "actionDone.xxx"
???
Profit!
EDIT: After re-reading your question, I'm going to lean more towards the second solution; by creating an intermediate page with a redirect (usually an HTTP/1.1 303 See Other) you can usually prevent this kind of confusion. Checking uniques on the database is always a good idea, but for the simple case of not wanting a refresh to repeat the last action, this is an elegant and well-established solution.
I'm currently working on a web app/game using C# and ASP.NET(3.5). However, I'm running into a problem of variables used in the main page being reset to null whenever I click a button on the web form. I'm wondering if there was a way to allow to variables to persist for the life cycle of the entire application, as well as for the variables to be accessed from wherever/whenever.
Another issue I'm having at the moment is that I can't seem to find a way to update the properties of controls, like text or colour, without having to refresh the page. Is there a way to update these properties "silently" without forcing the user to go through the whole page refresh cycle?
Thanks
Use Session collection to persist for a particular user. Alternatively use static variables to keep their values for the lifetime of the application domain (for all site users until the web server restarts or crashes).
To update page portions "silently" wrap them into UpdatePanels (Microsoft AJAX library thing) or use JavaScript (you can use some JS library like jQuery to make it easier and handle the cross-browser compatibility for you) to manipulale the structure of your document on-the-fly.
It really depends on the purpose of the variables, and their scope.
For variables that are different for each visitor, you want to place those variable into session.
For variables that are global to your whole app, and are the same for every visitor, then you can either use static variables, or put them into web.config as Application Settings
Changing text/color on the client, this sounds like you might need to make use of some javascript. JQuery is a javascript library that makes a lot of those type of manipulations easier.
You might have ViewState disabled at Page Level (or application level).
Usually ASP.NET stores the state of each control within the current page in the Viewstate Object to preserve their status over reloads. Have a look at the EnableViewState object in your code (Front End) or dig into the web.config.
If you also want data to persist at page level, use the Session object and work around the timeout property to find a suitable value that will work for you and your users. SlidingExpirationg could also be useful. If you are going to use this solution you might also ask yourself some questions. Is your application using 1 single server or is likely to be deployed to a server farm? If so, consider using SQL Session State instead of InProc as it will provide a more consistent "centric" place to stored the session data consumed by different servers.
Regarding updating controls without a page refresh you are looking for something called Ajax. Microsoft has release ASP.NET Ajax Toolkit, have a look at it, especially the asp:UpdatePanel which will let you "partial update" pieces of the page without reload everything else.
It's the easiest, straight forward, way to update controls properties without much effort.
Additionally, to update the client side objects without a postback to the server, you'll need to use javascript. jQuery will probably be your best bet.
My checkout process has the following workflow:
checkout page
shipping address
edit shipping address(add/edit)
delivery method
payment
place order
Each of the above steps has its own action in the same controller.
Now the issue is, if the person gets to #5, and wants to edit the address, they go back to #3.
But when they hit submit, they go to the next step, #4, but they should go straight back to #5.
I know I can pass information via a query string/form and tell #3 to check for the presence of that key, if its there, then redirect to #5.
Are there any proven, best-practice techniques to manage a workflow like this in asp.net-mvc (or in general)?
Usually I will set up a session to store the state and data of the user, and from determine which step to go on to next. Hence the controller upon being invoked could run some logic to determine which state the user is at, and then invoke the rendering code to output the form associated with the user's current state.
IMHO, this streamlines the process as you don't delegate the 'what's my next state' checking to the forms level, but to a centralised location, which makes it easy to add in new business logic down the road.
Hope this helps!
(You could replace session with invisible form fields, query strings and etc.)
If you really do "hate sessions" as you say, there is potentially another option, which is to pass a querystring for all "backward" operations defining where to go next.
This is how most Login pages work -- if you are not authorized to view a page, it will redirect to the Login page with a redirectUrl querystring parameter set. Then on successful login you'll be redirected to the page you originally came from.
And just to simplify your code a little you could overload the RedirectToAction() method on your controller such that it redirects to the given action UNLESS there's a that special querystring, in which case it redirects there.
edit: I know that you mentioned this as a possibility, but I posted it anyway because:
1) there's nothing wrong with it (especially if you "hate sessions"), and 2) you mentioned having your Action check for the presence of the key, which I think could be better written as I described (using an overload -- DRY)