Process get and post - asp.net-mvc

I have an question about the get and post process in ASP.NET MVC 4.
I'm sure that often talk about but it isn't easy to search for this topic.
Let me try to explain:
I start my controller with the standard method:
[HttpGet]
public ActionResult Item()
So, in this function I retrieve a lot of important data as example the user id and so on.
In my case, I even collect data in my viewbag() to decide if a form has to be displayed or not.
Now, if I start a post back:
[HttpPost]
public ActionResult Item(FormCollection formCollection)
the function gives as standard View() back.
The Problem is now, that after the post method, the business logic (retrieve user id and so on) of the GET method isn't called... I have tried to solve it with
return this.RedirectToAction("Item");
but is that really the solution for repeat the logic out of the start (get)? And how can I give the new values from the post method to the get method?
Best regards,
Patrik

That pattern is called Post/Redirect/Get.
To pass additional data to GET method you can use TempData and ModelStateToTempDataAttribute from MvcContrib - it passing ModelState to tempdata if Redirect is returned and tempdata to modelstate if View is returned.
[HttpGet]
[ModelStateToTempData]
public ActionResult Item(int id)
{
// prepare view
return View();
}
[HttpPost]
[ModelStateToTempData]
public ActionResult Item(FormCollection formCollection)
{
// do some business logic
int id = service.DoBusinessLogicAndReturnSomeId();
return this.RedirectToAction("Item", new { id });
}
You should avoid to have business logic in GET. All business logic should be inside POST method and after you invoke that you can redirect to GET where you prepare your view.

Related

return RedirectToAction("Edit", Model)

Afternoon Folks,
I have a question in reference to how to redirect to another model within my mvc project.
I have a controller with CRUD operations, and i have a [HttpPost] action on Create. The system saves the data to the database as required but instead of me sending the user back to the "Index" page i want to sent them to another model.
I know how to use the redirect option...
// POST: CarerDetailsNew/Create
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(CarerViewModel carerViewModel)
{
if (ModelState.IsValid)
{
db.CarerDetails.Add(carerViewModel.carer);
db.SaveChanges();
return RedirectToAction("Edit", carerViewModel.carer);
//return RedirectToRoute("ClientRecordsController");
}
return View(carerViewModel);
}
However i have read that i may be able to use the "RedirectToRoute" option to get back to another model.
The model that i am in is my "Carer" model but i want to get back to my "Client" model and specifically the "Edit".
I have tried to replace my RedirectToAction to one of the following but this fails to see the "Client" model.
return RedirectToRoute("Edit", clientViewRecord.client);
Or
return RedirectToRoute(ClientRecordsController, "Edit", clientViewRecord.client);
Any suggestions are more than welcome as i am struggling to get this to work.
Regards
Betty

MVC detect when model is empty

I'm new to MVC, so I'm trying to figure out some best practices.
Suppose I have a controller HomeController method Index(MyViewModel model):
public ActionResult Index(MyViewModel model)
{
//if loading the page for the first time, do nothing
//if the page has been posted data from somewhere, then I want to use
// some of the arguments in model to load other data, like say search results
}
When I navigate to the /Index page, I (myself) expect the model object to come through as null, but it doesn't. MVC (somehow) creates a MyViewModel for me.
My question is, what's the best way or most consistent to determine if model was created automatically, or via a post?
Ideas:
Create a property on MyViewModel that gets set when the view is posting back
Check for if the Request.HttpMethod == "GET" or "POST"
Something else?
You should use different actions for your GET and POST requests. Don't try and make a single method do too much.
[HttpGet]
public ActionResult Index()
{
// handle the GET request
}
[HttpPost]
public ActionResult Index(MyViewModel model)
{
if (ModelState.IsValid)
{
// it's a post and the data is valid
}
}
The correct method will then be called depending on whether it's a GET or POST
Create two actions, one which accepts a model instance and one which doesn't.
Even though you're "going to the same page" you are in fact performing two distinctly different actions. The first action loads an initial page, the second action posts some value to be acted upon. Two actions means two methods:
[HttpGet]
public ActionResult Index()
{
// perform any logic, but you probably just want to return the view
return View();
}
[HttpPost]
public ActionResult Index(MyViewModel model)
{
// respond to the model in some way
return View(model);
// or return something else? a redirect? it's up to you
}
Note that this kind of breaks your restful URLs. Consider semantically what you're doing in these actions:
Viewing an index
Posting to an index
The first one makes sense, but the second one probably doesn't. Normally when you POST something you're doing something related to a model or action of some sort. "Index" doesn't really describe an action. Are you "Create"-ing something? Are you "Edit"-ing something? Those sound like more meaningful action names for the POST action.

Overloading in MVC

I read here that I can't overload actions in MVC because of routing confusion
I tried to overload Index() in HomeController and I got the exception as article said, but I noticed that
microsoft has overloaded the actions in AccountController
public ActionResult Login(string returnUrl){}
public ActionResult Login(LoginModel model, string returnUrl){}
Please need clarification, thanks
Microsoft has overloaded this by setting HttpGet and HttpPost. One for GET request and another for POST request. What about your code?
[HttpGet]
public ActionResult Login(string returnUrl){}
[HttpPost]
public ActionResult Login(LoginModel model, string returnUrl){}
Till today you cannot overload your controller's Action method with same name but different parameters.
The only possibility is to have two overload, and for that you need to set the method's property to HttpGet and HttpPost. For example
[HttpGet]
public ActionResult foo(string myString)
{
return View();
}
[HttpPost]
public ActionResult foo(MyViewModelClass object)
{
return View();
}
And regarding your confusion,
From general convention, first method should be of type Get which gets called when someone sends request to access that page.
Second method is called when user submits a form with his login details.
In AccountController first method works with GET method, second with POST one. It was realized by attribute [HttpGet] and [HttpPost].
Read more about get and post here.
In addition to above answer we can add name attributes along with HTTPGET and HTTPPOST as
[HttpPost]
[ActionName("Edit")]
public ActionResult Edit_Post(some parameters)
{
//code over here
}
After this we can call it as :- /MVC/EmployeeController/Edit/1
Some definitions first:
Overloading is a form of polymorphism, in particular an interface, in the sense of a class publicly visible part, related one.
When we speak about inheritance we mean overriding.
Action is a segment of a URL.
Back to your question...
It is the ControllerActionInvoker which is responsible for finding the method to which an action is mapped. Given GET and POST we see polymorphic methods in a class mapped to the same action, but serving different HTTP methods (any action, that is, URL segment polymorphism here?!). And again yes, we may use ActionNameAttribute (MVC v5) to map an action to a class method, but again, this has nothing to do with any sort of polymorphism. Simply put, all that happens is in the ControllerActionInvoker and has nothing to do with overloading or overriding, and finally with any sort of polymorphism -- it is just mapping.
Conclusion.
A simple question arises:
What in a string (a segment of a URL, 3.) relates to any one of the OOP definitions (1. and 2.) above? Or, in other words, can any of the OOP concepts above be transformed to a (part of a) string?
The fact that a transformation between URL segment, which happen to be called "action", and a class method exits does not imply that all we know about the first mechanically can be applied to the second and vice-verse. The question is misleading and its main intention is to confuse someone, not to test his/her knowledge (I suspect that this is an artificial interview questions, not a real one).

Is it possible to have duplicate action names and parameter list for post and get?

is it possible to have 2 actions with the same name and parameters but one's a post, the other a get? e.g Delete(id) and [HttpPost]Delete(id)...i get an error saying that this is not allowed...
Yes, it's possible. Just use ActionName attribute on one action:
public ActionResult Delete(int id)
{
//...
return View();
}
[HttpPost]
[ActionName("Delete")]
public ActionResult Delete_Post(int id)
{
//...
return View();
}
The reason you get the error that it is not allowed is because C# itself gets confused. While in MVC you can add attributes to specify whether a function is HttpGet or HttpPost, that doesn't help C# determine the difference between one or the other. In order to have 2 functions with exactly the same name, the parameter list needs to be different.
As frennky pointed out, the ActionName attribute works in MVC because MVC uses aliases as part of the process for determining which action to call (along with attributes, but not parameters).
As a side note, it's probably best not to have a Delete action on a GET request. You don't want a crawler or some other bot accidently hitting the wrong link :P

ASP.NET MVC, JSON post to controller action with FormCollection parameter

I have a bunch of controller actions mostly used for saving data to backend storage. For now most of them use a signature like this:
//
// POST: /WidgetZone/Create
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(FormCollection collection)
as you can see, it accepts FormCollection. This works fine with classic user views. Now I want to JSON- enable these actions. And I do it using JsonPox action filter like this:
//
// POST: /WidgetZone/Create
[JsonPox]
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(FormCollection collection)
Will this work when the action expects FormCollection?
For instance this work without issues (of course I construct Json object in my JavaScript client-side to pass it into this action):
//
// POST: /WidgetZone/Create
[JsonPox]
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(string id, string description)
It is all about a task of converting postback UI into asynchronous one, so that saves and updates would be done async. Am I on the right track? I do think that developing separate Json, XML or classic ViewResult actions is not the best way to go.
Help appreciated
This filter is based on the the OnActionExecuted method which is run after the action method is executed in order to JSON or XML serialize the returned model. What you have as input to your action method is not important. Once the action finishes execution the filter will look for the model that you stored in the ViewResult and serialize it according to the Content-Type header that's passed in the request.

Resources