Maintaining values of action variables in between different requests - struts2

I am struts2 for developing my application.
Sample code of action class would be
class sampleAction extends Action {
private List<Employee> employee;
public validate(){
--logic for validation
}
public String prepopulate(){
--logic for populating value of employee list
}
--getters and setters
}
Now my problem is on page load i call prepopulate function and populate the value of employee list. After page submit validate method is called and during that if some error happens control redirects to jsp. but this time the value of employee list is empty. I am using this list for autocompleter tag in struts2.

I have never used Struts 2 built-in validation mechanism, as I prefer client-side validation to avoid an extra round trip. This is purely a personal choice and not a standard.
First I will suggest you not to use Action and use ActionSupport: ActionSupport provides a lot of functionality out of the box and you need not to do everything yourself.
I am assuming that you are using defaultStack and if this is the case than it provides out of the box Prepare Interceptor which takes care of preparing any values before the action itself is called.
In your case, validate is called before the execute method, so you never will get a chance to re-fill the values you need in your JSP.
All you need to make sure that you have prepare() method in your action class. Here are more details for this interceptor:
Prepare Interceptor
FAQ: How do we repopulate controls when validation fails

Related

Custom method on form submission with Umbraco Forms

What I'm trying to achieve is to customise what happens during the HttpPost/OnSubmit of a form created with Umbraco Forms, whilst still maintaining the default behaviour of the form and any subsequent workflow.
In my specific scenario, I need to be able to analyse the input of the form and based on that input I will send the user to a different "thank you" page, whilst also storing some elements of the originally submitted form in TempData.
I've tried the following:
I've tried to create a DocType controller (RenderMvcController), but this only allows you
to override the HttpGet, and not Post.
I cannot use a SurfaceController as I lose the functionality of the
module, Umbraco Forms.
I've tried to use a custom workflow, but this runs asynchronous to
the user's journey and I cannot change their experience.
There isn't much useful documentation available for this at all and I'm finding this task more difficult than I expected it to be.
In order to add a custom procedure after the submission of the form, and based on this procedure change the user journey you must do the following:
Create a new controller and inherit from UmbracoFormsController and override the OnFormHandled method
public class CustomUmbracoFormsController : UmbracoFormsController
{
protected override void OnFormHandled(Form form, FormViewModel model)
{
// Find the field in the form, then search for a matching value
var field = form.AllFields.FirstOrDefault(x => x.Alias == "deliveryOptions");
var fieldValue = model.FormState[field.Id.ToString()].GetValue(0).ToString();
// Add the value to the TempData
TempData["deliveryOptions"] = fieldValue;
}
}
The above is a basic implementation that doesn't account for NULL
Update the reference to UmbracoFormsController in /Views/Partials/Forms/Form.cshtml with your new controller from above.
...
#using (Html.BeginUmbracoForm<CustomUmbracoFormsController>("HandleForm"))
...
In the above example we analyse the form data and store some information in the TempData, we can set the form to redirect to a generic thank you page in which we can analyse the values in the TempData and change the view the user sees.
Also, if you are making changes to the Form values and what these to be updated, you'll need the Record Guid, which you can retrieve from TempData["Forms_Current_Record_id"] in conjunction with a new RecordStore object.

MVC4 Action method AutoMap actionfilter fails to convert the view model to domain model

so, I've seen this working on a previous project in MVC3, so wondering if a) i've screwed it up, or b) MVC4 is doing something different (can't see it would be).
I have a model bound Razor view which submits to a controller action method (as is the way with MVC)
post action method:
[HttpPost]
[AutoMap(typeof(MyViewModel), typeof(MyDomainObj))]
public void PostAction(MyDomainObj obj)
{... etc.. etc..
The action filter eventually does something like this:
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var model = filterContext.Controller.ViewData.Model;
NOTE: In Jimmy Bogard's example he used OnActionExecuted which I also tried..
The key issue I'm having is that at the pint where we get the "model" variable from the context, it's null. If I look at the filterContext.ActionParameters whilst debugging I can see a MyDomainObj instance!! which appears to (because it happens to have a prop name in common with the MyViewModel type) have been mapped from my form data!
So.. yes if I had MyViewModel type as the parameter to this method, then the param would be properly populated from the submitted form. But. I don't want to do that, I want to (and have done before based on JB's succinct how-to) converted the view model to domain model as part of the action executed/ing and then been able to just hit save on my domain model.
Summary - why is my ViewData.Model null on the post action filter?
Jimmmy also has/had a couple of ideas on how to implement post actions, along with another guy Matt Honeycutt who shares his view on how to do posts. I also believe Jimmy has gone in the direction of using explicit mapping in his get requests instead of attributes, as it can be hard to inject any extra code you need after mapping.
http://lostechies.com/jimmybogard/2011/06/22/cleaning-up-posts-in-asp-net-mvc/
http://trycatchfail.com/blog/post/Cleaning-up-POSTs-in-ASPNET-MVC-the-Fail-Tracker-Way.aspx
For a post you really want a couple of things imo, the original Entity and the Form Data. You could load the entity like you do for the GET request and do normal model binding to get the form data (remember you can accept a different model for post backs than you spit out in your view) then make the changes in the action.
Of course this would require using AutoMapper in your action, which you seem to be trying to avoid. But unless you write a custom model binder then you're not going to magically get the formdata in a model as the built in one looks at the action paramters to figure out what to bind. For this reason i'd recommend not using a domain model as a parameter for an action, as it may fill out fields that you don't wish it to.
I've also seen Jimmy using a ModelBinder to do something similar to your AutoMapGet, which may be another alternative method, but I'm guessing you've seen that post.
My standard post takes Matt's approach, moving the validation out into a global attribute so it can't be forgotten (there are some downsides to this) then accepting a new view model explicity for the form data, then I explicity load the entity, use automapper to update it and call save. Most the actions only end up being about 5 lines long.
I do avoid using the static methods on AutoMapper and pass a IMapper in via constructor injection. This allows me to make it a bit more testable if I really need to, however the methods are normally so simple the tests don't add all that much value.

Struts2 - validation failure using xml file causes action class paramters to disappear from resulting jsp

I have a class A :
class A extends ActionSupport{
int someId;
// getters/setters
public String execute(){
setSomeId(2);
return SUCCESS;
}
public String save(){
// something
}
}
In struts.xml, I have configured an action "ViewId" that takes us to the default method execute, where someId is set. Then, we are taken to a jsp page show.jsp where I can access the someId value. In show.jsp, I have to enter an email id and then submit the page. The action that's now called in "Save" that takes us to the save method of the action class. But, I have given some checks in the corresponding validation.xml file A-Save-validation.xml, which will check the email entered for a format. The problem is that if the xml validation fails, we are taken back to show.jsp, but the viewId parameter is now not available. Why is this so ?
The input page should appear similar to the user as before. Only the fields that are now validated should have an error page associated with them. Any workaround for this ?
Like #Umesh said, validation happens on the corresponding interecptor, before the action's method is called.
When validation fails, the action's method is never called and you will be taken to the INPUT result.
In order to achieve what you want you have some options:
Implement the preparable interface in your action
Peform the validation inside your method.
Use s:action in your jsp before the items you want populated to call an action that populates the relevant section
1 is probably the easiest. I like option 3 as well.

Overloading of public functions in Controller

I am new to MVC. I was going through the asp.net site and found this link where it stated that public methods (actions) cannot be overloaded in controller classes. However in the site it stated that it can be only be possible if i use [AcceptVerbs(HttpVerbs.Post)] with one function.
Can you please explain how does AcceptVerbs helps in overloading the function.What it actually does behind the scene?
And in one of my sample application i am able to overload the function by using [HttpPost] in one function.What else can be used for overloading?
Basically the rule is that you can handle this when it is responding to different types of requests, so Post/Get/Delete. (Any of the items in the HttpVerbs enumeration)
It is due to the way that it does resolution of the method to call in the controller, and specifying the method allows it to handle resolution.
In ASP.NET MVC, incoming request url should match action of controller. In MVC request processing pipeline, first the controller action is selected, and then the parameters for it are inspected and populated. Imagine what happened if controller had two methods with same name but different signature (overloaded).The c# compiler does not complain, as it understands the code, because it can distinguish between methods based on its parameter signature. But ASP.NET MVC request matching mechanism, as mentioned above, cannot - it first does search for action and only after action is selected, it takes look at its parameters. Because of this, "Public actions in controllers cannot be overloaded" - if there're no difference between methods(actions) other than parameters, action selection in MVC will fail to unambiguously select one. This's where ActionMethodSelectorAttribute comes into play. This is the base mechanism for developers to affect the way MVC searches for valid action in specified controller. It has the method IsValidForRequest() that tells MVC wether action can be selected for usage or not. All of [AcceptVerbs], [HttpGet], [HttpPost], [HttpPut], [HttpDelete] and [HttpNonAction] derive from this attribute. And bingo - now the method overloading is possible - although actions have got the same name, one of the attributes above (or your custom attribute derived from ActionMethodSelectorAttribute) can tell MVC wchich action to select and which one to not. And MVC now unambigously knows wchich action is valid for request. Consider example
[HttpGet]
public ActionResult Index()
{
// The above HttpGet.IsValidForRequest() called internally
by mvc will return true only if request is made via HTTP GET
}
[HttpPost]
public ActionResult Index(MyModel model)
{
// The above HttpPost.IsValidForRequest() called internally
by mvc will return true only if request is made via HTTP POST
}
// And so forth with other ActionMethodSelectorAttibute s. As you see, only one action from same named ones is valid for single request when decorated with any of builtin ActionMethodSelectorAttibute

struts2 drop down

I need to create a drop down menu in struts2 from List. How can I create an action class so that when a .jsp page is loaded, it populates the list first?
i found this link http://www.mkyong.com/struts2/struts-2-sselect-drop-down-box-example/ , it works too but for it work user must go to http://localhost:8080/Struts2Example/selectAction.action to make it work but what if someone were to directly go to select.jsp.
Since you're using a .jsp, you could load the dropdown with a scriptlet before you render the <s:select> tag.
However, it's better practice to allow the action to perform the loading and hide the .jsp files under /WEB-INF so they're not directly accessible. A common approach to perform this is the Prepare interceptor.
If you've got it in your interceptor stack, it will automatically invoke any method with the following name in your action before invoking the requested method:
prepare{MethodName}()
prepareDo{MethodName}()
prepare()
That means you can do something like the following in your Action:
public class YourAction extends ActionSupport {
public String prepare(){
// populate your drop down object
}
public String view(){
// forward to your jsp
return SUCCESS;
}
}
Then all you have to do is call your action's view() method and prepare will be called first by Struts.

Resources