Is it considered better practice to post back to the same controller that did the rendering and redirecting from original controller if necessary? Or is it just the same if one jumps to different controllers from the view?
I create two overloaded actions in the controller, one to render the input form using an HTTP GET and the other to process the form post using an HTTP POST. Something like this:
public ViewResult Foo()
{
return View();
}
[AcceptVerbs(HttpVerbs.Post)]
public ViewResult Foo( FormCollection form )
{
// process input
if (inputOK)
return RedirectToAction("Index");
return View();
}
The benefit of doing it this way is that if there's an error, the view gets re-rendered with any error and validation messages. If it's successful, there's a redirect to another action, which avoids the duplicate posting warning on browsers if a user refreshes the page - see Post/Redirect/Get on Wikipedia and this blog entry by Stephen Walther.
There are alternatives to taking a FormCollection, e.g. a list of simple parameters or binding to an object. See this article by ScottGu.
I think that the action that is being called should be contained within a relevant controller for that action. If the view needs to call the action it should call it from the relevant controller, not necessarily the controller that it was spawned from.
If you have an inventory controller you don't want to define actions that relate to administration even if an inventory screen might have an administration action on it, as an example.
Related
As I have read that once you set a tempdata, it will last till next request and if you need to use it more then we need to use keep. But in this situation there is somewhere my tempdata is being lost.
The scenario is below:
I have a view and corresponding to that I have a action method in my controller and here I just set a tempdata as below:
Controller class:
public actionresult myview()
{
tempdata["Empid"]= sourceid;
}
The view consists of several renderAction as below and all these actionmethods in controller return some partialviews
#html.renderAction("details","mycontroller")
#html.renderAction("details","mycontroller")
#html.renderAction("details","mycontroller")
#html.renderAction("details","mycontroller")
Now in partialviews, I have several ajaxified calls suppose in one of the partialview , I have a post method using ajax like below:
$.post("action", "controller",{}});
Please ignore syntactical mistakes as I only have problem in understating the logic of tempdata.
So, coming to above, now the post methods have actionmethods that uses the tempdata that i have set when my view page loads i.e tempdata["Empid"] because this tempdata is needed to get details of employee.
So, it gets the data, reurn json formatted data and I show it in view perfectly.
Uptill here everything is fine. Now, I have one of the partialviews that uses the ajax post to hit controller which is not the same controller but a different cs file. Here this tempdata goes off.
Why is it happening so..
TempData is designed for a short life by default. So the data you set to TempDataDictionary object persists only from one request to the next request. After that it is not going to be available.
You can use the TempDataDictionary.Keep() method to persist the value for the next request again.
public ActionResult Index()
{
TempData["Message"]="Hello";
return View();
}
public ActionResult GetCustomer()
{
var msg = TempData["Message"] as string;
TempData.Keep("Message");
return View();
}
In the process of updating a C# MVC 2.0 application!
I have a view “Signup” and another view “ForgotPassword”.
Each view have a with a submit button.
Each form is submitted to the same Controller but to two different ActionResult:
[HttpPost]
public ActionResult Signup(SignupModel signupModel)
{…}
[HttpPost]
public ActionResult ForgotPwd(ForgotPasswordModel forgotPasswordModel)
{…}
Upon completion my goal is to redirect the user to a “thankyou” page but based on where the user is coming from (either Signup or ForgotPassword) I wish to display a particular message (or a different UI).
Inside the same Controller, I created a “Thankyou” ActionResult:
public ViewResult Thankyou()
{
return View();
}
I was thinking of adding a parameter to my Thankyou() method which would allow me to know where the user is coming from (Signup or ForgotPwd). From there, make the “thankyou” page display the appropriate UI/message.
I’m looking for a clean and simple solution.
Should I create two View User Controls and show the appropriate one based on the parameter being passed?
In addition, instead of having an “ActionResult” for my Thankyou() method couldn’t I use a “PartialViewResult” ?
EDIT:
I was actually considering something along those lines…
Where ThankyouType is an Enum.
[HttpPost]
public ActionResult Signup(SignupModel signupModel)
{
//Validation code...
return View("Thankyou", ThankyouType.SignupDone);
}
[HttpPost]
public ActionResult ForgotPassword(ForgotPasswordModel forgotPasswordModel)
{
//Validation code...
return View("Thankyou", ThankyouType.ForgotPasswordDone);
}
And then have my “Thankyou” ViewResult like this:
public ViewResult Thankyou(ThankyouType type)
{
return View(type);
}
Doesn’t seem like I can create a strongly typed view based on Enum (unless I’m wrong).
Perhaps I’ll read more on PartialViewResults and/or find examples…but then again, I could be completely wrong.
I would personally give the ThankYou view a model that has the message you want to display, and have your two controller actions render the ThankYou view directly on success rather than calling a ThankYou action.
However, if you're sure you want a redirect, you may consider using the TempData collection to store a message or a key of some kind. The ThankYou controller can then retrieve this value and pass it to the View. This situation is what TempData was made for.
Edit
There's no reason you shouldn't be able to use an enum value as your model type, but if that gives you trouble you should at least be able to create a model type that has an enum property on it.
The strategy of sending the ThankYouType as part of the redirect request would work just fine, if that's what you prefer. The only potential downside is that it would look like this in the URL:
http://domain.com/controller/ThankYou?type=ForgotPasswordDone
I have no real arguments against it. There are lots of options. Use the one that feels best to you.
I have a partial view that shows a list of Categories. I'd like to put that partial view on any page, but I'd like to have it to call to the service and get a list of categories by itself without me having to do that in every controller action. Something like webforms in which you can put a code-behind on it.
For eg.
Actions
public ActionResult Index()
{
JobListViewModel model = new JobListViewModel();
model.Categories= jobService.GetCategories();
return View(model);
}
public ActionResult Details(int id)
{
Job job = jobService.GetJob(id);
return View(job);
}
I created a partial that will take the model.Categories model and display a list. As you can see, the Index page will work fine, but I do not want to call it again in the Details page. Is there a way to make my partialview call to the GetCategories() service by itself?
Use Html.RenderAction - that gives the partial view its own controller action.
You should also mark you partial action with the attribute [ChildActionOnly].
DVark,
As noted in the accepted answer, for your scenario, RenderAction is the most appropriate.
I thought I'd link a little article that distils my thinking on the topic (i.e. when to use RenderPartial vs RenderAction):
http://cbertolasio.wordpress.com/2010/09/21/mvc-html-renderaction-vs-html-renderpartial/
hope it helps
[edit] - as an aside. a year or so ago, i got myself into a few scrapes by not appreciating the power of RenderAction, in favour of RenderPartial. as a result, i had littered the shared view space with lots of partialviews in order to access them from a variety of sources. the moral of the story: know your 'territory' before planting your flag.
I'm experimenting with different combinations of strongly typed view models, full views and partial views, using both RenderPartial() and RenderAction(). The form-post scenario I'm asking about, though, is one that comes from the "main" view--one that isn't a partial. This main view's controller constructs the view model that provides the partial views with their models.
The [HttpPost] action is also in the main controller, and accepts a single object:
[HttpPost]
public ActionResult Edit([Bind(Prefix="Book")]Book book)
When the ModelState is valid, and the update is successful, I use a RedirectToAction(), which is all fine.
When there are errors in the ModelState, however, I attempt to:
Return View(book);
-and the view, of course, is expecting the "main" view model object that contains all kinds of other objects and Select Lists, etc., which is the problem.
In this case, do people use the whole view model object as a parameter to their [HttpPost] action, so that they can pass it back if there is an error? I know this can't be right, but rather think there is an easier solution that I am unaware of.
One common pattern worth considering is PRG or Post-Redirect-Get.
If validation fails, redirect to the original Get action, if validation passes, GET your next page in the sequence.
HTTP GET of "/products/create", "Create" view is rendered
HTTP POST to "/products/submit"
Validation Fails, redirect to "/products/create", "Create" view is rendered
HTTP POST to "/products/submit"
Item is created, redirect to "/products/confirm", "Confirm" view is rendered
I'm writing a simple blogging platform with ASP.NET MVC. My question is regarding forms contained in partial views and handling the response, validation errors or success, from the controller.
I have a blog post item view which has an associated controller that returns a post for a given URL. Embedded in this view is a partial view containing a form for submitting comments on the post. The partial view form submits to a separate controller that handles adding comments. Inside the add comment action I perform validation and add errors to the ModelState object.
The problem is that I have to return a RedirectResult on the partial view action so that the user is returned to the originating post item, which means that I lose the ModelState object or any success messages I want to return.
I've seen people mention the use of TempData to pass validation or success information back to the original view, but to me this sounds a bit hackish. Is this really the solution? If so can anyone recommend a good example of its usage? If not, is this a sign of bigger problems in my chosen architecture?
I have used the PRG Pattern in the past give it a try
Use PRG Pattern for Data Modification
You can have the add comment action call the view post action...
Something like this I guess:
public class PostController
{
... blah ...
public ActionResult ViewPost(int postId)
{
Post post = PostRepository.GetPost(postId);
return View("ViewPost", post);
}
public ActionResult AddComment(int postId, string comment, string otherInfo)
{
//Validate stuff, setting modelstate etc
//If it isn't valid, return the same post view (modelstate will stay)
if (!ModelState.IsValid)
return this.ViewPost(postId);
//If it is valid then we want to save it and follow PRG pattern
PostRepository.Save(newValidComment);
TempData["Message"] = "Thanks for your comment!";
return RedirectToAction("ViewPost", new {id = postId});
}
}
Or a variation of the same concept...
HTHs,
Charles
Have you considered using the Ajax libraries to just post that area of the page? That way you wouldn't need to redirect.