MVC Render Action on Post - c#

I have a page that calls another partial view. The page loads fine, but when there is a validation error, it appears to call the post method multiple times.
The code that is causing the issue is here:
<div>
#{Html.RenderAction("ViewUploadedDocs", "TrackingHome", new { number = #Model.Id.ToString() });}
</div>
This should call the following method in the controller.
public ActionResult ViewUploadedDocs(string number)
{
return PartialView();
}
It is not decorated with [HttpGet] or [HttpPost]. The method that keeps getting called is below which is the post method of the page.
[HttpPost]
[MultipleButton(Name = "action", Argument = "Save")]
public ActionResult Edit(EditScreenModelValidation model)
{
if (ModelState.IsValid)
{
return RedirectToAction("UserWorkflows", "Home", new { Area = "Workflow" });
}
return View("Edit", model);
}
I have read on stackoverflow where people have the page calling the post method that they are trying to get, but mine is calling the post method of my main page and not the page that I am trying to get. If I remove the renderAction line in my main page, then the page works correctly, and the action does not call the Edit page in it.

RenderAction invokes the specified child action method and renders the result inline in the parent view (it calls the action). You should use RenderPartial if you need to pass the current ViewDataDictionary object or Partial if you need the specified view to be rendered as an HTML-encoded string, depending on what you're trying to accomplish.

Related

Controller redirection doesn't change view

I'm doing a simple RedirectAction in my controler and in this new Controller i'm calling the new View, however in the Browser the View is not changing, i can see in the cshtml the code getting there, but i don't know what i'm missing.
public ActionResult ExecuteBreakdown(string param1)
{
return RedirectToAction("ShowMatrix", "BreakdownMatrix", new { param = param1 });
}
public ActionResult ShowMatrix(string param1 )
{
...lots of code
return View("ShowMatrix", priceMatrix);
}
I'm not being redirect to the ShowMatrix View.
You need to return something like a PartialView in your redirect to action call. However, the call needs to be scoped to a parent view that can display the partial properly. You can't just load what you send over like that.

model data disappears between controllers

So i have a model with two models in it so that i can render to different views on the same view, one login view and one register view.
This is my model:
public class SignUpLoginModel
{
public LoginModel loginmodel { get; set; }
public RegisterModel registermodel { get; set; }
}
And when i am trying to register a new user with this controller method:
public ActionResult Register(SignUpLoginModel model)
{
if (ModelState.IsValid)
{
// Attempt to register the user
try
{
WebSecurity.CreateUserAndAccount(model.registermodel.UserName,
model.registermodel.Password,
new
{
FirstName = model.registermodel.Firstname,
LastName = model.registermodel.Lastname,
Country = model.registermodel.Country,
City = model.registermodel.City,
Birthdate = model.registermodel.Birthdate
});
WebSecurity.Login(model.registermodel.UserName, model.registermodel.Password);
return RedirectToAction("Index", "Home");
}
catch (MembershipCreateUserException e)
{
ModelState.AddModelError("", ErrorCodeToString(e.StatusCode));
}
}
// If we got this far, something failed, redisplay form
return RedirectToAction("Register", "Home", model);
}
So the modelstate.isvalid failes as it should and it redirects to the home controller and the register method and send the model. Here everything works fine, the model contains the data. But when i redirect to another controller
public ActionResult Register(SignUpLoginModel model)
{
ViewBag.Message = "RegisterFail";
return View("Index", "Home", model);
}
my model ends up with null instead of the right data. What am i doing wrong?
I'm pretty sure it's because RedirectToAction (neither the overload you are using nor any of the other signatures) doesn't forward your model for you. It sends a 302 back to your browser which then issues a new GET request to a new url - therefore your model data is lost.
So you'd need to do something like this in the first controller
{
TempData["signupModel"]=model;
return RedirectToAction("Register", "Home", model);
}
and then this in the redirect controller:
public ActionResult Register(SignUpLoginModel model)
{
ViewBag.Message = "RegisterFail";
return View("Index", "Home", TempData["signupModel"]);
}
But what I don't understand is why you don't just directly return a view the first time around, why do you need to redirect - because from your code you seem to be just redirecting back to the same controller - or have I missed something?
Edit based on comments below
I honestly think you would be better off using Ajax for this because what you're trying to do here is maintain state across multiple controllers/views which is not really idiomatic for MVC.
If you submit the "register" popup form via Ajax, then you never actually leave the Index page, you just execute some code server-side and return some JSON to indicate if your registration was OK or not. When this response indicates an error you can just display an error message on the popup form or whatever, otherwise you can redirect to wherever on the client-side.
OR
When your Register controller decides that registration has failed, return the Home page index view e.g
ViewBag.Message = "RegisterFail";
return View("~/HomePage/HomeController/Index.cshtml", model); //or whatever the virtual path to the home page view is
However I don't like this approach as it sounds to me like you have your register form HTML being generated in-line by the the Home page view, which sounds like mixed concerns to me.

Html.ActionLink on Post Methods

Is there any way that I can use a html.actionLink to post data?
public ActionResult Test()
{
return View();
}
[HttpPost]
public ActionResult Test(TestModel test)
{
return View(test);
}
and on my view...
#Html.ActionLink("ClickMe","Test", new {Test1 = "actionLink", Test2 = "actionLinkDidThis"}, FormMethod.Post)
Is there any way that this action link could get in the httpPost method and not the httpGet method?
This will render an anchor tag which will produce a get request since it's a regular hyperlink at the end of the day.
You can Make the action method a Get method though by putting a HttpGet attribute on it instead. The MVC model binder will be able to deserialize the Get request into the TestModel object for Get requests as well.
I would use a button and do a form post if you need a post request

How to use RedirectToAction while passing view model to a view with different route

I have a ASP.NET MVC 3 app with a common scenario where there is with an "About" controller using "Contact" and "ThankYou" actions.
I want user to go to /about/contact, fill out the form, submit it, and be taken to /about/contact/thankyou * page where the form contents (aka view model) will be displayed.
** Note there is no "Contact" controller nor do I want to create one for this purpose if possible.*
I am using RedirectToAction to prevent resubmission (Post/Redirect/Get pattern) and TempData to pass on view model to thank you page.
I can also use TempData to check if thank you page was reached directly and redirect back to contact form page (so it would not register as a "goal" in web analytics)
But one thing I could not figure out is how to use different route for thank you page so it appears as /about/contact/thankyou
Am I doing this right?
Is there a better way?
Here are relevant actions in AboutController
<!-- language: c# -->
[RequireHttps]
public ActionResult Contact()
{
var viewModel = new ContactViewModel();
return View(viewModel);
}
[RequireHttps]
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Contact(ContactViewModel viewModel)
{
if (!ModelState.IsValid)
{
return View(viewModel);
}
// not sure if this is the best way or how to redirect to /contact/thankyou
TempData["viewModel"] = viewModel;
return RedirectToAction("ThankYou");
}
[RequireHttps]
public ActionResult ThankYou()
{
var viewModel = TempData["viewModel"];
// upon direct access, viewModel will be null and missing, so redirect to Contact form
if (viewModel == null)
{
return RedirectToAction("Contact");
}
return View(viewModel);
}
You could define a custom route before the default route:
routes.MapRoute(
"contact",
"about/contact/thankyou",
new { controller = "About", action = "ThankYou" }
);
Now when you navigate to /about/contact the Contact GET action will be executed (You have to rename it as in your code it is called ContactUs). Then the user fills the form and submits to the Contact POST action. The url stays the same for the moment: /about/contact. After the redirect the ThankYou action is executed and the url changes to /about/contact/thankyou.

Can I share a view in asp.net mvc?

My controller has 2 actions:
Results()
Index()
I want to share the view named index.aspx between these 2 actions.
See my previous post for more information
When I build my link to the page, I assume I cannot send it to Index action as it is expecting a FormCollection type and hence I create a Results action
public ActionResult Results(ClientSearch data, int? page)
{
FormCollection collection = new FormCollection();
collection.Add("FNAme", data.FName);
collection.Add("Lane", data.Lane);
collection.Add("Zip", data.Zip);
collection.Add("Phone", data.Phone);
return Index(page, collection);
}
Not sure I completely understand your question, but if you want to use the same View on different ActionResults, you can:
public ActionResult One() {
// do stuff
return View("Index", myModel);
}
public ActionResult Two() {
// do stuff
return View("Index", myOtherModel); // Same View
}
Just make sure you are providing the same Type for the View (if the View needs a Type at all).
Of course you can. It's up to controller to decide how to react and what view to serve back.
Now that I've read your question to the end :)), well, you can get away with two actions of the same name. The one will be accepting GET commands (initial load of the page), the other will be serving POST requests, perform the necessary action and redirect back to the same View.
public MyController
{
[AcceptVerbs (HttpVerbs.Get)]
public ActionResult Index ()
{
return View ();
}
[AcceptVerbs (HttpVerbs.Post)]
public ActionResult Index (ClientSearch data, int? page)
{
// Process form post
return RedirectToAction ("Index");
}
}

Categories

Resources