Im a new ASP MVC learner, Im working on a small pieces and getting stuck. The scenario is that user is creating new account in which accountID is automatically created by SQL. I want to pass this ID to the next step, let user input name and address. How would I pass this ID or any solution for this scenario? Think about passing data by TempData or Session but I'm not sure.
TempData will save the data until the end of your subsequent request.
There is also ViewBag/ViewData, which are really the same dictionary, are shorter lasting and they last only until the end of the current request.
Session lasts for as long as the user's session is open.
I believe TempData fits your bill, if "next step" means passing the data to a subsequent view, but if you need the data to be more durable, Session is the way to go.
I think you are approaching this incorrectly. You should have the user fill out all the information first, and then do all the registration, including creating the user and storing the data from the various steps all at the end.
If you do things the way you suggest, you will end up with partially registered users. They will create an account, and then maybe close their browser and never finish the rest. You will now have to write extra code to check all this every time they log in.
It's better to simply have your registration process do this all at once as an all or nothing process.
Just use the same process you would use for your login form. If the user is already entered in the database, you might as well treat them as a logged-in user that does not have a fully filled profile, yet.
In ASP.NET MVC, this would - in a lot of cases - be solved by setting the Forms Authentication cookie to the newly registered username
FormsAuthentication.SetAuthCookie(newUser.Logon, false);
I think that storing the user id in TempData or Session is the wrong scope for that. For all normal purposes, a user that just registered to your website can be treated as logged in after the record has been inserted in the user database.
You can try this way -
Create the user (username and password will be the values from your form):
WebSecurity.CreateUserAndAccount(username, password);
And then do this:
int userID = 0;
userID = WebSecurity.GetUserId(username);
Hope that helps.
Related
I have one method which receive two parameters (int?, string). Action in my controller must save this variables and return view with form. After form is returned from client I need this variables from previous request. I can pass them to view with ViewBag and add to form as hidden, but it is very dangerous, anyone can change it in browser. Any ideas?
I think this question does not make sense.
If I have method which receives two parameters with HTTP GET method, so it's no difference where user change this two variables, in get method or in form.
If I store it in server side, he can change when passing parameters to first method and server will store wrong variables.For example:http://www.someurl.com/Controller/Action/?id=123&key=someKeyI can change parameters by editing url, so absurdly store it as variable at server side to make sure that user wouldn't change it by editig hidden fields. Moreover I can check if key is the same key as in database with this id.
Session time is 20 or 30 minutes. User can open this form and submit it when the time of session is out. Users don't like exceptions
It's pretty standard to allow forms to expire after a certain amount of time. You can keep sessions open forever as that's a security hole.
As for the actual value, you can remove it from the session as soon as the second page has been processed. If the value is not there when the second page is hit, simply redirect to the first one again and show a message that says that it took too long time.
Your second option is to use TempData with is specifically designed for storing values between two pages. TempData cannot be accessed by the user.
The third option is of course to store the value in a database (to keep it as long as you want, between logins etc)
You can store any object you like in the current session of the user. In your controller you can use:
// Save value to session
Session["MyVariableName"] = 32;
// Read value from session
int myVariable = (int)Session["MyVariableName"];
For more info regarding the session see: https://msdn.microsoft.com/de-de/library/system.web.httpcontext.session(v=vs.110).aspx
I am writing an application in asp.mvc. I have a view that displays a Product with specific id and on with that view user can modify the Product. There is a dropdown list with colors, that user can select. Range of available colors depends on user's permissions, not all users have access to all colors.
When user clicks "Save" button an ajax request us sent to server with ids of Product and selected color.
Here is the problem:
When user opens the page I check if he is authorized to edit the product with id provided in url and I display only those colors that user can access. But I have no guarantee that user modifies the ajax request sent when he saves the Product. So I can display Product with id 1, and colors with id 12, 13, 14, but user can manually alter the request and change Product id to 3 (which he is not permitted to edit) and select color to 15 (which he shouldn't even see).
In good old webforms this wasn't a problem, because id of product could have been saved in viewstate, and on server side I checked which index of dropdown was selected and then I knew what is the id of selected item (stored in viewstate or controlstate). How do you solve this problem in MVC? Do I have to check if user has access to each element twice, when I display the data and when I receive it, for example in "Save" request?
Even ViewState without protection and care can expose your web server to malicious content. Please note:
Because it's composed of plain text, the view state could be tampered with. Although programmers are not supposed to store sensitive data in the view state (credit card numbers, passwords, or connection strings, for example), it goes without saying that the view state can be used to carry out attacks on the server. View state is not a security hole per se, but just like query strings and other hidden fields you may have used in the past, it's a potential vehicle for malicious code. Since the view state is encoded, protected, and validated, it does provide more security features than other hidden fields that you may use for your own programming purposes.
as Dino Esposito states here.
You've got three options:
Protect (encrypt) your hidden fields (current productId and colors) and validate them on server after a user posts.
Use sessions (store current user's working context, i.e. productId and colors), in case option 3 is too resource consuming or you don't want to maintain huge amount of validation logic on server.
Validate permissions for the objects after user posts. In case option 2 cannot be accepted (you don't use sessions at all).
I agree with RononDex's answer. Session provides you with an easy means of storing data on the server for the user, without exposing that data in way they can manipulate.
So you could store the product ID like so:
Session["ProductId"] = however you get the id.
Plus you can store the colours:
Session["Colours"] = // Whatever you want, an array of int or List<int>
There are caveats with session state though, including that it can be wiped, be it by an expiration of that session (which you can control the number of minutes before that takes place), or an application pool refresh, so bear that in mind.
This might also be good reading for you:
http://brockallen.com/2012/04/07/think-twice-about-using-session-state/
So there are pros and cons to session state. If you decide to not use session state, and instead store the ID values in hidden fields in the HMTL, then please do consider hashing, or encrypting, those ID values so that a user cannot see what they are, or try to alter them.
TempData is used in cases to maintain state, it is stored on the server for one user request.
I have an application that shows many charts and tables using JQuery. Some of these charts are based on variables that are saved in the session (E.g. user added a value in another page and in the next page I am generating a chart, so the user request doesn't send any parameters)
I was looking around on the net and most of the solutions are based on
[OutputCache(Duration=60, VaryByParam="someParm")]
The problem is most of my request don't send parameters, they just use values that are in the session.
Is there any way to enable cache for these kinds of requests?
Edit: We have a complex security requirement that we couldn't use the default authorization attribute of MVC. We had to write logics based on the current user + the parameters sent to the action, so a method inside the action decides either to go ahead with the request or returns nothing. This makes caching very difficult because at the time OutputCache is executed we just have parameters, but identity object in the context is empty. As a result, if a user with admin privilege send a request for a and b and after him someone with minimum privilege send request for a and b, the second person will see the result because the action didn't run, but the value from the cache is used!
To solve this problem I used the getvarybyCustome. All this function does is to return user's group name which helps to create a more complex key. The person with minimum privilege in the last example will have different cache key (a,b,group_less) than the admin's request cache key (a,b,group_admin). However, getting's group name for each request is expensive as well, so I use Cache object to cache user's group, so at the beginning of the session the user's group is queried from AD and saved to cache, so for his/her later requests, his group name is retrieved from cache.
If something you can't achieve by VaryByParam then you can try VaryByCustom. See an example here
You could make a redirect of this request and send it to a new controller method sending the session parameters, by this way in a future implementation may be you use query string parameters instead of session and your code will work too.
You could make a method for conversion of this session parameters on a base class of all your controllers, to write the conversion once.
I am using the Redirect After Post pattern in my ASP.NET MVC application. I have
the following scenario:
User goes to /controller/index where he is asked to fill a form.
Form values are POSTed to /controller/calculate.
The Calculate action performs calculation based on input and instantiates a complex object containing the results of the operation. This object is stored in TempData and user is redirected to /controller/result.
/controller/result retrieves the result from TempData and renders them to the user.
The problem with this approach is that if the user hits F5 while viewing the results in /controller/result the page can no longer be rendered as TempData has been expired and the result object is no longer available.
This behavior is not desired by the users. One possible solution would be instead of redirecting after the POST, just rendering the results view. Now if the user hits F5 he gets a browser dialog asking if he wants to repost the form. This also was not desired.
One possible solution I thought of was to serialize the result object and passing it in the URL before redirecting but AFAIK there are some limitations in the length of a GET request and if the object gets pretty big I might hit this limitation (especially if base64 encoded).
Another possibility would be to use the Session object instead of TempData to persist the results. But before implementing this solution I would like to know if there's a better way of doing it.
UPDATE:
Further investigating the issue I found out that if I re-put the result object in TempData inside the /controller/result action it actually works:
public ActionResult Result()
{
var result = TempData["result"];
TempData["result"] = result;
return View(result);
}
But this feels kind of dirty. Could there be any side effects with this approach (such as switching to out-of-process session providers as currently I use InProc)?
Store it in the Session with some unique key and pass the key as part of the url. Then as long as the session is alive they can use the back/forward button to their heart's content and still have the URL respond properly. Alternatively, you could use the ASP cache, but I'd normally reserve that for objects that are shared among users. Of course, if you used the parameters to the calculation as the key and you found the result in the cache, you could simply re-use it.
I think redirect after post makes much more sense when the resulting Url is meaningfull.
In your case it would mean that all data required for the calculation is in the Url of /controller/result.
/controller/calculate would not do the calculation but /controller/result.
If you can get this done thinks get pretty easy: You hash the values required for the calculation and use it as the key for the cache. If the user refreshes he only hits the cache.
If you cant have a meaningfull url you could post to /controller/index. If the user hits F5 calculation would start again, but a cache with the hash as key would help again.
TempData is generally considered useful for passing messages back to the user not for storing working entities (a user refresh will nuke the contents of TempData).
I don't know of more appropriate place than the session to store this kind of information. I think the general idea is keep session as small as possible though. Personally I usually write some wrappers to add and remove specific objects to session. Cleaning them up manually where possible.
Alternatively you can store in a database in which you purge stale items on a regular basis.
I might adopt a similar idea to a lot of banks on their online banking sites by using one-time keys to verify all POSTs. You can integrate it into a html helper for forms and into your service layer (for example) for verification.
Let's say that you only want to post any instance of a form once. Add a guid to the form. If the form does not post back and the data is committed then you want to invalidate the guid and redirect to the GET action. If say the form was not valid, when the page posts back you need a new (valid) guid there in the form waiting for the next post attempt.
GUIDs are generated as required and added to a table in your DB. As they are invalidated (by POSTS, whether successful or not) they are flagged in the table. You may want to trim the table at 100 rows.. or 1000, depending on how heavy your app will be and how many rendered but not yet posted forms you may have at any one time.
I haven't really fine tuned this design but i think it might work. It wont be as smelly as the TempData and you can still adhere to the PRG pattern.
Remember, with PRG you dont want to send the new data to the GET action in a temp variable of some sort. You want to query it back from the data store, where it's now committed to.
As Michael stated, TempData has a single purpose -> store an object for one trip only and only one trip. As I understand it, TempData is essentially using the same Session object as you might use but it will automatically remove the object from the session on the next trip.
Stick with Session imho rather than push back in to TempData.
I'm trying to send the user id (integer) from a view to the action. If I pass it using routevalues object, the user id will be visible in the browser address bar.
How can I pass user id from view to the action without using aforementioned method??
You can use a hidden input element inside a form. You should generally use POST, not GET (i.e. use a form, not an a href) for anything that is changing data in your system.
The user id is commonly inferred from your authentication mechanism (cookie etc), so for the current user you shouldn't need to pass it around.
The main time you would include this in the request is when the page being displayed relates to users - and in particular where you (or an admin) want to browse other users records - then you might use "/users/current/orders" (use the cookie) or "/users/12345/orders" (and you should verify permission to browse 12345).
Note that if you use /current/ or similar, you should ensure it isn't cached between different users - so in many ways it is simpler to just show the user-id and to heck with the url; just go for the simple "/users/12345/orders" case.
What is the scenario here?