Struts2 how to keep form values when navigating between pages? - struts2

I’m using struts2 + spring3 for my project. Please help me to resolve this problem.
In my app, (a.jsp) relate to --> (aAction.java).
From the main menu, user can access a.jsp. There are so many fields in the a.jsp that user need to key in data. In the middle of the page, user needs to go another page (b.jsp) to add some more details. (b.jsp page is not a popup window) After adding data to b.jsp, user needs to come back to a.jsp. How can I retain a.jsp page data?
Only one action use for both pages (aAction.java).
1) I can keep hidden variables in b.jsp and populate data again in a.jsp. But there are so many
fields in a.jsp. So this way is tedious.
Is there any way to handle this problem with bean scope? Or any other way to do?

There are several ways to do this
use redirectActions in struts.xml. When defining results you can set the type to redirectAction. Then you can redirect to another action and pass params that will be added as parameters to the url
http://struts.apache.org/release/2.1.x/docs/redirect-action-result.html
use localStorage instead of session storage. Limit is 5 MB. Care needs to be taken when using session storage as it can affect the server's performance
if you are using struts, you can make your own type converter for passing any object. Alternatively you could create an string array of the values you want to persist and pass it as a param in struts.xml (see above). Struts has built in type converter for persisting string arrays between pages/actions
you could also save them in cookies and then delete the cookies as soon as the values are not needed as there is a limit on the number of cookies browsers can support
I usually use session storage as a last resort for the reason mentioned above

Related

How do I maintain a specific query string across all requests?

If someone goes to our website with a query string key of ref (for example mysite.com/AboutUs?ref=Test), is it possible to maintain that query string on all future links/form posts?
So for example, I may have a link on our website to go to mysite.com/Products. I would want this to be translated into mysite.com/Products?ref=Test.
Ideally I want to know if this is possible to do by inspecting the previous URL and adding it to the current URL when the request for the page is made, maybe by intercepting the route and appending the key (if it doesn't exist already).
The project is an MVC 4 application.
You could actually pass it along by adding it to every single URL, but that would require manually adding to each use of Html.ActionLink, etc. (or I suppose you could create a custom HTML Helper to do that for you, but then every developer who works on your project would need to remember to always use the custom helper), as well as all redirects and such in your controller actions. Long and short, this would be very time consuming and very fragile.
Your best bet is to simply intercept the initial request with the querystring parameter and then set a session var. Then, you can simply check for the presence of the session var instead of the querystring parameter.
To handle all this logic, your best bet is to create a global action filter. There's pretty extensive documentation on Filters at MSDN. Once you create your filter, you just have to register it in FilterConfig.cs (in App_Start) to make it global.
Set the URL parameter in a cookie, and later in your code do whatever you want to do based on presence of that value in either the cookie or URL.
if(parameter set in cookie OR URL)
// do stuff
if(parameter set in URL)
// set the cookie so that future actions are also tagged with that parameter
Alternatively if you want such tagging to happen only for the session, set a session variable.
To do it in the way you suggested - You could rewrite all links on your page based on this tag, but that would be a roundabout, and costly, way of doing this. Most languages allow a hook that allows your code to process the HTML output before it is sent out to browser; just run a appropriate regex search and replace to get what you want. e.g. PHP has ob buffering and associated functions. You could use the equivalent for .Net.

MVC Passing Data as Hidden (Not in URL, not as Hidden HTML)

I'm using MVC 3 C#.NET.
Is there any way to pass values between pages (two different page with different controllers) without exposing the value in the URL or as hidden values? Is the last resort using a Session variable? Or would you recommend encoding the hidden field (ala ViewState style) and parse that to the controller?
I'm passing several values that I want hidden from the user as they might try to play with the values.
Any suggestions?
Simply use a POST and hidden fields in your form. POST fields do not show up in your URL only GET's. Always try to minimize the use of session variables, those should be used to store user login information, user settings, preferences, etc.
Simply persist this data in some backing storage on your server (could be a database or whatever backing storage you are using). I am not fan of a Session myself so I don't recommend it using it at all. If the user is not supposed to see or modify this data, then this data should not even be passed to the view. It should stay where it belongs => on the server.
I still used hidden fields, but encoded it to Base64, ala ViewState style. It obscures the real values for most users.

MVC Cache Based on Variables in Session and Custom Security Logic

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.

ASP.NET MVC : Create an ambient value

I have a simple web-site. Almost every action takes int toonId as an argument (toonId does not equate to the user: one user can own multiple toons).
At the moment I provide that value to every view from controller, and every link and submit button sends this value back to the controller.
This works. I am just looking for an easier way to accomplish this (AOP comes to mind).
I use cookies to persist "favorite/default toon", and this works fine (used with ActionAttribute, that takes toonId from cookie and passes is to the toonId argument, if toonId wasn't provided). But I want to support cookie-less sessions as well.
Question: What is an easy way to add ambient variable to the page, without passing it explicitly all over? Such that it would work with cookie-less browsers.
Is Viewstate a way to go (which isn't supposed to be in the MVC)?
Is server-side session a way to go?
This is exactly what session is meant for.
There is no page lifecycle in asp.net mvc, hence no viewstate.
I believe you can automatically pass query string parameters for use cookie-less browsers if you plug in your own implementation of IRouteHandler. I have not tried it though. I found an example of implementing IRouteHandler although it does not show how to implement the query string parameter functionality.
I'm not clear on what 'toonid' represents. If it's 'ambient per user session', then as womp stated, Session state would work well for this. However, if it's somethign that has a larger scope (e.g. a colleciton of toonids that are commonly accessed by all users) then teh Cache would be a better and more scalable strategy.

Redirect After Post in ASP.NET MVC

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.

Resources