I have written an application in ASP.net, that is designed to let the user add records to a database. The page is set up that when a user adds a record, the ID number of the newly added record is set in session, the page Response.Redirects to a "Thank you for submitting" page, then redirects back to the original page to allow further edits. Users can also use the Back button on this screen to go back to the original record adding page, which allows them to make edits to the data.
However, I have found that storing the ID in session isn't a terribly good solution, as a user might try to create two documents in different tabs or windows. I have also tried setting the ID in a literal control, but this causes the problem that when the user uses the Back button, the literal control isn't set to the ID, and new records get added instead of one being edited.
Is there any kind of solution for this?
I'd recommend storing your ID in the QueryString. After the record is added, redirect to your "thankyou" page, which then I am guessing contains a link to the edit form which you will generate with the ID in the querystring. When that link is followed, the edit page shouild pull the ID out of the query string in order to load up the correct record to edit.
Your add and edit form can even be the same page, when an ID is provided in the querystring, your form knows to edit that record, otherwise your form adds a new record.
Silly question, why can the user use the back button to edit the data just accepted in a post?
If the edit previously posted data is a common scenario why not just redirect to a page when the data is accepted that lets them edit it. Then if the hit the back button they would be going back to the original "clean" insert/add new data page.
This would give the following flows
Add->[Post]->Edit->.....
Add->[Post]->Edit->[Back button]->Add->[Post]->Edit->[Post]->Edit....
Have you tried adding the ID in the querystring? Then you could read it, and add it to the session as needed (say on a user clicking the back button).
Seems like a lot of problems allowing editing of an object in a page rendered when using the back button. Would it be too much to give them an edit button instead?
The controls save their state in the ViewState. If you choose to use SessionState instead of ViewState to store the information, then the controls will save their state in the session state and it won't work properly with multiple tabs.
I have not yet found a way to bypass this issue while still using SessionState. Our solution was to use the normal ViewState.
I've tried storing the ID in the querystring (which is mostly fine for editing), but the problem with that is when the information is stored in session for when they use the Back button. If the user does the following:
User creates a record (1st record), the ID is passed along in the querystring, and temporarily stored in session.
User creates another record (2nd record), the ID is passed along in the querystring, temporarily stored in session.
User uses the Back button on the first record to go to the page that doesn't have the querystring.
It's probably a far-fetched scenario, but it's one that may happen. The only solution I have is to block the usage of the Back button to go back to the adding page, by using window.history.forward() in JavaScript. But this as a solution is terrible.
My question for you is why are you storing anything in the session to begin with? If you can avoid storing anything in the session, I think you will be better off altogether.
Having thought about this, does the following sound like a decent solution to the problem I outlined above?
When first adding a record, store a timestamp of when the add page was accessed in a hidden field.
This timestamp is passed through session when the user clicks save. Along with the ID.
If the user opens another tab at the same time and saves, then the new page's timestamp gets passed through session.
If the user tries to access the add page of first record (using the back button), the system looks up session, and sees if there is a timestamp, and whether it matches the one in the hidden field for that page.
If it doesn't match, then the user gets a prompt, and told to edit the record properly.
Does this sound reasonable, or too overly complex?
Related
I have a Layout page which sets up the list of Projects in the application using Telerik's ComboBox as shown. The combobox allows user to select a project he/she wants to work on.
Once a selection is made, I want all subsequent actions in the application should correspond to the selected Project. I can preserve the Project information in a Session but then if user chooses to open this in a new tab and in 2nd tab users switches to a different Project and comes back to the first tab and refreshes the page then the session information (Project) would have changed which will create issues in my application.
So, what is the best way for me to persist Project information of the Layout.cshtml controls so that I can use it in my application such that every page that is rendered uses the currently/correctly selected values.
Tempdata / QueryStrings came to my mind but i don't know whether they will be reasonable solution to my problem. If yes, then how should I use them generically (specially querystrings) without complicating my solution?
localStroage and sessionStorage also seems like relevant solutions but then how do I use them in scenario where user opens a new tab from existing page? How will the Project # will persist on the newly opened page/window/tab?
something like this is achievable, if you make sure the url changes when a selection is made.
So let's say you select project C-1379 in your dropdown box, at that point your url could become http://localhost:58692/pid=C-1379.
from now onwards, your page can load the desired data, retrieving its required information from the query string. Do not use session or localstorage or anything like that as it won't work.
This way, you can still load your list of projects in your layout page, and you can select one based on the query string value and then load some default values via api calls to the back end.
If all your work from now on is done based on api calls, for example, you have some properties that you change and then you issue a POST to update said details then this is very easily done as well.
telerik controls usually have some events associated with them. the one you are using should have an onChange or something like that. This where where you would update the query string with the value of the project selected and then you can proceed to do what you need
I can preserve the Project information in a Session but then if user
chooses to open this in a new tab and in 2nd tab users switches to a
different Project and comes back to the first tab and refreshes the
page then the session information (Project) would have changed which
will create issues in my application.
I would have thought this is the desired behavior... take stackoverflow.com as an example, if I change my username in one browser-tab, I would expect my username to be updated in other browser-tabs as well... and that's what happens if I refresh my other tab.
There is no built in solution for maintaining user info in different browser tabs separately... the only way to achieve this, is by sending project name back and forth in the URL... but then you would loose this info if user changes the URL... In my opinion, this is an ad hoc solution and does not worth the effort of development, because it's a very uncommon scenario.
Getting to your options:
Storing user info is a very typical use case for session variable.
TempData is stored in Session by default. Though you can write
your own custom TempDataProvider and store it somewhere else (e.g.
database, cookie, etc). See Brok Allen's Cookie TempDataProvider
as an example. One advantage of using Cookie is that you send your
session variable back and forth with the request so you don't need to
worry about Sticky Sessions.
You can of course use a permanent storage, such as DB/Disk.
If the project name is not a sensitive info then I don't see any issue in passing it in Query String.
I have page where users can select from one or more images. When they are done I would like them to navigate to the next page and what is displayed would be based on the selection from the previous page.
"Selecting" just means that they click the image and it has a CSS class added to it. When they click the link to navigate to the next page I'd like to collect the images that have been selected and pass that information along using either TempData or Session.
In most of the examples I have seen either inputs or the query string is used to pass information from the View to the Controller. How can I pass which elements have a particular class to my controller when a link is clicked?
If you're using a link click, I'd probably just append the selected images to the query string. I'm assuming you don't mind exposing this query string to end users.
I'm sure that's probably not the answer you were looking for. But as you stated I think you're only to legitimate options are passing the values through the query string or using hidden inputs and posting the page to your action by intercepting the link click event.
You said you do not want to post back to servers. You cannot access TempData or Session without posting back to server, so they are out of scope.
You only have client side option, so you want to collect a user's selected items in array.
Once the user clicks to Next Page, you create a query string like this ?ids=1-2-3-4 and retrieve those value at next page.
Other thoughts: Long URL likes this is a bit ugly, and URL has maximum length limit depending on browser. If I'm you, I'll post back to server to collect the selected values. Then use TempData (or some persistent storage).
I have 2 views in my SPA built up using durandal. I have a form (consider basic employee information form) in the first view. Also, I am having a button in the view called "upload" which routes to a different view to upload some documents. Once user finishes uploading, it redirects back to my first view and when it does, the first view reloads (renders) again loosing all my previously entered values. Same is the case when I press browser back button on my second view (the upload page).
Any solution on how I can persist data in this case ?
Thanks.
Posting code would make it a bit easier but I would think you'd need to maybe store what's entered in LocalStorage or something and then retrieve it later?
AmplifyJS can make this easier.
The problem that I am having is as follows:
I currently have a custom class that generates buttons and places them on a placeholder on a master page.
The events for these buttons put specific values into session that differs values for a database query. In essence, the buttons serve as filters for charts.
After creating all the buttons, I realized that session values will stay constant from page to page, so everytime a user enters a different page while another is open, the filters selected on the open page will remain constant for the new page that is opened.
At first, I wanted to use viewstate rather than session, but then realized that a master page and a content page do not share the same viewstate.
At the current time, I am thinking of using a prefix for the sesson key that will identify what page the filters actually exist for. However, I am not wanting to overload session with numerous values if the user wishes to have many pages open at the same time.
Any solutions that would entail a way to share viewstate (or some other way to store values) between app_code, the master, and the content page?
Use HttpContext.Current.Items, it is a key-value pair collection with a lifetime of a single Http Request.
Have you considered Context.Items?
How many filters are we talking here? Store the filter values in the URL. Have you seen some of the URLs that google or an ecommerce site uses? They are quite long. Here is how I do it:
I store the filter values in the query like, www.chart.com?filter1=val1&filter2=val2 etc.
I user JQuery's query plugin to manipulate the query on the client side, and then request the chart from the server again, using the new query.
This way, I'm not junking up session, cookies, or anything like that, and if the user wants to store a bookmark to a particular chart or email it to a friend, they can and the filters are preserved.
I'm starting to think the answer shown in the following question will work:
ViewState object lost in Master Page Load
Exposing the desired variables via a property.
If the data isn't too long, cookies are a typical solution.
Another option is to use Silverlight isolated storage. The Silverlight control itself could be invisible (no UI).
I want to redirect the user to another page to fill out a captcha but i would like to keep the post data, and if the captcha pass to send it 'back' and complete the previous page action.
When/if the user succeeds i like to add an captchaPass=true and would like access the post data and continue processing. Right now i am using redirects but ATM i am not required to use it.
Is it possible to carry the post data? keep in mind i may the user access multiple pages so separating data and not having a mixup is necessary.
One idea is to get and save all posted data [1] on the captcha page, and then recreate a middle white page with this form data and automatically make a new post to the previous page.
Can this work with out any issues with hash checks and security ?
Is there a better idea with out this white redirect page ?
[1] One other issue here, how to send this posted data with the redirect ? and not change the url - or make it too big to accept it. Keep in mine that a server transfer may not good idea because is complicate the thinks on captach post back.
Update 1
The basic idea here is how some one capture the full post back of a page, show a different one page and then send the post back data to the original first one.
The reason is to stop a bad user, or an attacker bot program that try to bring down the pages/server by making many post back from different pages in short time. All that happens with out javascript, and most attackers use custom made programs that just make post of data to all page together try to bring down the system.
For example, if a page have a search box, is very easy for most of the the site to bring them down by start making hundred of random search with wildcard (called and Dos Attacks using SQL wildcards) and make the sql server and the computer spend his time and cpu to search and search thinks. So to prevent an attack like this you need to recognize multiple post backs from the same computer, and then the next step is to redirect him to a captcha page to block him out in case that is a computer program.
Other example, many page have email submit, very easy you can submit hundred times the email of his and full his mail box in no time with hundred of emails, or on a store to place all items on the cart again and again and full the database with stuff like that.
So ajax and javascript is not working in this case, and we need a way to redirect him after the post back to a page that can check if is a real user or an attacker and stop him - but if is a real user must return back to his normal action.
Update 2
This all must be done in a general way, eg on BasePage, or on Global.asax or somewhere that is independed from the content of any page. Because we try to prevent a DoS attack, or multiple submit anywhere on any random place of any random page.
Yes I know how you can place a captcha on the contact page, but this is not what this question was first asked for - this questions asked how can carry post data to one different page, keep them there and then resend them back to the original one.
The obvious solution is to read all post back, and save them on the form, and then read them back and make on fly a form only with that data and make the post back. Here I am asking if there are any other better than this solution.
Other Applications
There is also the case that a user is inside a page that request authentication, but the authentication ticket has expired, and the user make post back. In this case we need to keep somewhere all the posted back data, to proceed with the login page, and resend them back to the first page that request the authentication.
Sure, just write the form data out to the captcha page in hidden elements with the additional captcha fields added to the form. Have your submit action post the whole thing back to the original. Using ASP.NET it's probably easier to have the captcha written to the same page with the form fields hidden, but you can do cross-page postbacks as I've described above.
Cross Page Posting might help you.
Why not implement the CAPTCHA with AJAX? Load the captcha object and form with Javascript in a div perhaps displayed lightbox style, accept the user input and post it to your server for validation, hence continue with the users post request or keep them there until they get it right (or cancel).
A more specific situation example:
Give the form submittal button an onClientClick value of some Javascript function. This function decides if this particular form needs a CAPTCHA. If it does it loads an interface for taking the CAPTCHA (which you'd need to do with some server-side code) and inserts the CAPTCHA's input element to the form that the user clicked to submit.
Once the user has entered the CAPTCHA input and clicks some button whose click event is bound to return to your first JS function, the Javascript intercepts this action and posts the full form, all the data from the original form and the CAPTCHA for validation. Your server script can now process all this at once!
This is the best solution I can think of that works similar to how you've asked, but I can't imagine why you want to perform the CAPTCHA on a different page.
Server.Transfer with MultiViews, Panels like control is fine with you? In this way, no need to bother about the Data Maintenance and Postbacks. You can do the validations in javascript.
You can keep both functionality in the same page to avoid moving data from one page to another page/Bring the data back to original page. You can utilize Session for this intermediate operation. Set it back to associated controls across Postback. You can create a class, Instantiate it and Initialize the control values in this class object. Save class object in Session. On Postback, You can reassign the values to the associated controls. This will definitely keep the things simple and without much complexity.
Doubts ?