Html.RenderAction uses Post instead of Get - asp.net-mvc-4

I have a simple form on my page. When submitted, it checks if ModelState.IsValid and returns the View with the same model if it's not valid.
On the same page, I'm rendering an action that contains another form like so:
Html.RenderAction("AccountNote", new { id = Model.ID });
Everything works fine until I submit the form on my page and the validation fails. When it shows the page again, the AccountNote action's Post event fires when I'd expect the Get event to fire. I guess it makes sense why it's happening since it's the post that action that's rendering the view, but I want the Get event to fire instead.
public ActionResult AccountNote(int id)
{
//code goes here...
return PartialView(model);
}
[HttpPost]
public ActionResult AccountNote(AccountNoteViewModel model)
{
//code goes here...
return PartialView(model);
}
Am I doing something incorrect? Or is there some trickery I have to do to make this work? I would expect the Html.RenderAction to always assume GET instead of POST.

One solution would be to have only one AccountNote() action method. Then it will be called regardless of GET or POST. You might have to modify your logic a bit if you were using POST version of AccountNote().
And you can decorate it with [ChildActionOnly] attribute.

Since I know, there is not any solution for this problem out of the box. RenderAction and Action methods, consider the current request for deciding on to use which verb.
But you can rename them. For example rename the one that is restricted to HttpPost to AddAccountNote and leave the other one with the current name and without specifying its verb.

Would RenderPartial be an option for you?
More discussion on this topic can be found here: RenderAction calls wrong action method

Related

Displaying error messages from Controller in View

I have seen a lot of people say that using Viewdata or ViewBag is not a good practice for this matter(displaying messages from the controller) because of security reasons. Everyone seems to suggest ModelState
My question is what is wrong with using viewdata to display error messages? If we arent supposed to use ViewData then what should we use it for?
As #shenku answered before, ViewData and ModelState reference the exact same thing, if you look at the code for System.Web.Mvc.Controller class you will see the implementation for ModelState is:
public ModelStateDictionary ModelState
{
get
{
return this.ViewData.ModelState;
}
}
and #JimmiTh said,
although the main use of ModelState from an "end developer"'s perspective is in the controller, ViewData is used as a container for all data that's communicated between the controller and the view. Which is why it also needs to include ModelState - because, although you'd rarely use it directly in the view, ModelState is where e.g. many of the HtmlHelper methods actually get the values from by default when rendering the view from a POST action - rather than Model.

How to create controller action for details view

Inherited a Sitefinity site. Need to add a MVC widget for the details view on the news pages.
I found this documentation but I can't make heads or tails of it - maybe it was for a different version. I finally found the UrlkeyPrefix buried deep in the news widget options, but following the instructions of the documentation added "!content" in the middle of my details page URL (which I can't have happening) and still did not display my custom widget.
Does anyone know how to correctly configure the controller to get the widget to show up for the details pages?
I sort of got the example in the documentation to work, except that there's this very annoying "!content" in my URL still
https://mysite/news/!content/2017/08/24/my-article-title
[ActionName("!content")]
public ActionResult Filter()
{
return View("index", InitializeModel());
}
Navigating to the URL sans "!content" just shows the list page.
The nature of MVC is such that you're only able to invoke one action at a time.
Assuming that you're invoking the Details action on the NewsController, the other widget you've placed on the page won't understand how to respond to a Details action unless you do one of two things:
Create a corresponding Details action in your own controller OR
Override HandleUnknownAction to handle what you want to happen when another widget's method is invoked. (better, as it reduces ambiguity)
If you want to invoke your Index action on your custom widget when the Details action is invoked on News:
protected override void HandleUnknownAction(string actionName)
{
this.ActionInvoker.InvokeAction(this.ControllerContext, "Index");
}

Can Umbraco pass a model to view

I am quite new to this Umbraco MVC.
I need to pass some data bound to a model to my partial view from the GET action method.
This simply is not working in a regular MVC way.
[httpget]
public ActionResult Membership()
{
SupplierMembershipInfoModel mm = new SupplierMembershipInfoModel();
mm.ProductPackage = "sssssssss";
ViewBag.status = Request.QueryString["status"];
return PartialView("MembershipPartial", mm);
}
my view:
#model Umbraco.Web.Models.SupplierMembershipInfoModel
some html.....
<td>#Model.ProductPackage</td>
I don't get data here...and the debug never hits the action. But it hits any POST action method.
I know i am doing something wrong...but just don't know what the mistake is??
Any ideas??
As #Sebastiaan points out, the best place to start is the Umbraco community site. There is documentation specific to your issue here: http://our.umbraco.org/documentation/Reference/Templating/Mvc/child-actions
In a nutshell, you want to display a child action on your page and Umbraco uses SurfaceControllers for this. A SurfaceController is simply a Controller that inherits from Umbraco.Web.Mvc.SurfaceController. This provides you Controller with access to the Umbraco context - see here (http://our.umbraco.org/documentation/Reference/Templating/Mvc/surface-controllers).
Either way, you should read the whole documentation section on templating as it will give you a lot of insight into how Umbraco MVC is managed.

Setting returnURL for CButtonColumn button

I'm looking at the controller for the default Delete button in the CButtonColumn class. It manages to return to the previous web-page after deleting a CGridView line and remain on the same page of the CGridView, as opposed to going to the first page. The lines responsible for this in the associated controller seem to be:
if (!isset($_GET['ajax']))
$this->redirect(isset($_POST['returnUrl']) ? $_POST['returnUrl'] : array('admin'));
I would like to create a new custom button that has this behavior (i.e. returning to the previous view without resetting the pagination to page 1), but simply including the above lines of code in the button's associated action does not do the trick. I think I need to send that 'returnUrl' parameter somehow, but I cannot figure out how :)
The 'returnUrl' code you are looking at uses a POST variable for the returnUrl. To use this, you will need to POST that somehow. On the View this code is called from I am assuming there is a <input name="returnUrl"> field in the form. You should make sure this field (populated with the correct URL value) is on all of the Views you are POSTing from in order to access that POST variable in your Controller action.
If you are POSTing to the deleteAction via AJAX, I think you can set the $_POST['returnUrl'] variable with the jQuery AJAX function.
Another way to go might be to use CWebUser's returnUrl SESSION variable instead of this POST variable. I have never done this, but it's built in to Yii so I assume it works OK.
I never really liked the hacky $_POST['returnUrl'] that Gii generates anyway.
ANOTHER thing you could do, possibly, is look at the $_SERVER['HTTP_REFERER'] variable, and use that for the return redirect in your deleteAction. I don't know if that will be set correctly though, with complications from the 302 redirect/rewrites that Yii does.
Good luck!
You can set the return url via the CHtml::link call. Here is an example using delete
CHtml::link(
'Delete',
'#',
array('submit'=>array('delete','id'=>$model->id),
'params'=>('returnUrl'=>'controller/action...'),
'confirm' => 'Are you sure?'
)
);
Pulled from this Stackoverflow answer.

A better way of passing variables from controller to view in symfony

Hey.
I've got a login form with post as method. The action goes to 'auth/login' and will check the database if the user exists. If the user exists, I call the $this->getUser->setAuthenticated(true);. After this I want to redirect to a welcome page if success.
If the login failed, I would want to tell the user so in the view of course. But settings variables in the controller only if login failed, and check in the view if each of those variables are set, is a lot of work?
This means I have to check almost all variables I want to use in the view set from the controller. If it should happen that it is not set, and I just go ahead and echo it, I get an error from symfony, and production stage-mode-ish don't show anything but an 500 internal server error .
Thanks
EDIT:
This is my current, new and better solution. Still looking for feeback.
in /templates/loginSuccess
if ($sf_params->has('bad_login')) {
echo "Wrong username or password";
}
And in my controller:
$this->redirect('auth/login?bad_login=');
Take a look at how sfDoctrineGuardPlugin (the de-facto standard for authentication) does it: they created sfGuardValidatorUser and use it as a post validator in the signin form.
Advantage of this method: the form takes care of the username/password validation, you do not need to put that code in your action. It simplifies that to a simple $form->isValid() { $this->redirect("#homepage"); }.
It seems like you could use symfony's form to take care of the validation. Since the forms show errors built in, you could put this into the form validation and then your controller looks something like:
$form = new LoginForm;
if ($request->isMethod('post'))
{
if ($form->isValid())
{
$this->redirect('account');
}
else
{
// this would show the form, and since you put the login in the form validation it will show errors. You could have the username show the error
}
}
To do what you are doing though, I'd recommend this. That way you aren't accessing any parameters in the view as well.
Controller:
$this->bad_login = $this->getParameter('bad_login',false);
View:
if ($bad_login) { echo 'bad login'; }
Use forward()
Put all the logic required for the view population into separate method of a controller, and call it in both places.
Use cgratigny's solution - put login form and processing code in a single action, and redirect to welcome page if isMethod('post') && $login_success