Use Get And Post in the same Controller - c#

I want to use the HttpGet and HttpPost attributes for one action method. However, I have only seen examples where the attributes are used individually on separate action methods.
For example:
public ActionResult Index()
{
//Code...
return View();
}
[HttpPost]
public ActionResult Index(FormCollection form)
{
//Code...
return View();
}
I want to have something like this:
[HttpGet][HttpPost]
public ActionResult Index(FormCollection form)
{
//Code...
return View();
}
I remember having seen this done somewhere, but cannot remember where.

If you really want to do that, you can use the [AcceptVerbs] attribute. (See this SO question)
This way your method can handle the GET and POST verbs (but not others like PUT)
[AcceptVerbs(HttpVerbs.Get | HttpVerbs.Post)]
public ActionResult Index(FormCollection form)
{
//Code...
return View();
}
If you want your method to handle all verbs, donĀ“t use any attribute at all:
public ActionResult Index(FormCollection form)
{
//Code...
return View();
}

Related

Return view from another post

This is my code:
[HttpPost]
public ActionResult Edit(int id)
{
var viewModel = service.GetUserViewModel(id);
return View(viewModel); // reponse the ValidateLogin view
}
[HttpPost]
public ActionResult EditDetails(UserDetails userDetails)
{
return Edit(userDetails.Id);
}
Unfortunelly it is not returning view, but it is giving me error. What's wrong there?
You cannot return view from another action marked with [HttpPost] by using return Edit(userDetails.Id), instead it's necessary to set one action as [HttpGet] (i.e. Edit action method) and use RedirectToAction() overload which has route value parameter to call that action like example below:
[HttpPost]
public ActionResult EditDetails(UserDetails userDetails)
{
// note: the second overload is routeValues
return RedirectToAction("Edit", userDetails.Id);
}
[HttpGet]
public ActionResult Edit(int id)
{
var viewModel = service.GetUserViewModel(id);
return View(viewModel); // reponse the ValidateLogin view
}

ASP.NET MVC Return Overloaded Get Action

I am using MVC 4, and I have the following:
[HttpGet]
public ActionResult SomeForm(modelType model = null)
{
if(model != null)
return View(model);
return View(getModelFromSomewhere());
}
[HttpPost]
public ActionResult SomeForm(modelType model)
{
if(isValid())
doSomething();
else
return SomeForm(model) // Line in Question
}
However, obviously, I am getting an ambiguous method error on "Line in Question". I'm wondering if anyone has an elegant solution to be able to specify to return specifically the [Get] method of the same name?
Thank you!
You can't have methods with the same signature as you've pointed out already. In C# it also means you can't distinguish functions by just return type - so you must use different names if parameters are same (again default values are ignored when matching of signatures).
If you want separate GET and POST handler - use different names of methods and ActionNameAttribute to name the action:
[HttpGet]
[AciontName("SomeForm")]
public ActionResult SomeFormGet(modelType model = null) ...
[HttpPost]
[AciontName("SomeForm")]
public ActionResult SomeFormPost(modelType model) ...
make it compile...
[HttpPost]
public ActionResult SomeForm(modelType model, FormCollection fc)
{
if(isValid())
doSomething();
else
return SomeForm(model) // Line in Question
}
If you are using http get method you are waiting that browser will send you serialized model as a string query. For example, you are waiting url like
http://example.com?name=Andrew&type=Worker&field1=param1&field2=param2&....
It is common practice to use only id in your get method, so you can do it like this:
[HttpGet]
public ActionResult SomeForm(int id)
{
var model = FindModelById(id);
if(model != null)
return View(model);
return View(getModelFromSomewhere());
}
If you are looking for an elegant solution, it will be more elegant in architecture

Already defined member called 'Search' with the same parameter types

I'm getting a confusing error and I'm not quite sure why. Usually this kind of error pops up when you have two ActionResults and forget [HttpPost] on one of them. But as you can see, I have [HttpPost] there, so what could be causing this problem?
Error: Type 'PersonalWebsite.Controllers.BlogController' already defines a member called 'Search' with the same parameter types Controllers\BlogController.cs
and the code:
//
// GET: /Blog/Search
public virtual ActionResult Search()
{
return RedirectToAction(MVC.Blog.Index());
}
//
// POST: /Blog/Search
[HttpPost]
[ValidateInput(false)]
public virtual ActionResult Search(SearchViewModel model)
{
// irrelevant code snipped
return View(model);
}
There are no other Search() methods defined in this controller. It's bizarre.
Any ideas?
Your Search method is already defined in another partial.
See here: https://github.com/Imdsm/PersonalWebsite/blob/master/PersonalWebsite/BlogController.generated.cs
[NonAction]
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
public virtual System.Web.Mvc.ActionResult Search()
You could create an alias for your method via:
[HttpPost]
[ValidateInput(false)]
[ActionName("Search")]
public virtual ActionResult SearchByPost(SearchViewModel model)
{
// irrelevant code snipped
return View(model);
}

GET and POST methods with the same Action name in the same Controller [duplicate]

This question already has answers here:
MVC [HttpPost/HttpGet] for Action
(4 answers)
Closed 2 years ago.
Why is this incorrect?
{
public class HomeController : Controller
{
[HttpGet]
public ActionResult Index()
{
Some Code--Some Code---Some Code
return View();
}
[HttpPost]
public ActionResult Index()
{
Some Code--Some Code---Some Code
return View();
}
}
How can I have a controlller thas answer one thing when is "getted" and one when is "posted"?
Since you cannot have two methods with the same name and signature you have to use the ActionName attribute:
[HttpGet]
public ActionResult Index()
{
// your code
return View();
}
[HttpPost]
[ActionName("Index")]
public ActionResult IndexPost()
{
// your code
return View();
}
Also see "How a Method Becomes An Action"
While ASP.NET MVC will allow you to have two actions with the same name, .NET won't allow you to have two methods with the same signature - i.e. the same name and parameters.
You will need to name the methods differently use the ActionName attribute to tell ASP.NET MVC that they're actually the same action.
That said, if you're talking about a GET and a POST, this problem will likely go away, as the POST action will take more parameters than the GET and therefore be distinguishable.
So, you need either:
[HttpGet]
public ActionResult ActionName() {...}
[HttpPost, ActionName("ActionName")]
public ActionResult ActionNamePost() {...}
Or,
[HttpGet]
public ActionResult ActionName() {...}
[HttpPost]
public ActionResult ActionName(string aParameter) {...}
I like to accept a form post for my POST actions, even if I don't need it. For me it just feels like the right thing to do as you're supposedly posting something.
public class HomeController : Controller
{
public ActionResult Index()
{
//Code...
return View();
}
[HttpPost]
public ActionResult Index(FormCollection form)
{
//Code...
return View();
}
}
To answer your specific question, you cannot have two methods with the same name and the same arguments in a single class; using the HttpGet and HttpPost attributes doesn't distinguish the methods.
To address this, I'd typically include the view model for the form you're posting:
public class HomeController : Controller
{
[HttpGet]
public ActionResult Index()
{
Some Code--Some Code---Some Code
return View();
}
[HttpPost]
public ActionResult Index(formViewModel model)
{
do work on model --
return View();
}
}
You received the good answer to this question, but I want to add my two cents. You could use one method and process requests according to request type:
public ActionResult Index()
{
if("GET"==this.HttpContext.Request.RequestType)
{
Some Code--Some Code---Some Code for GET
}
else if("POST"==this.HttpContext.Request.RequestType)
{
Some Code--Some Code---Some Code for POST
}
else
{
//exception
}
return View();
}
Can not multi action same name and same parameter
[HttpGet]
public ActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult Index(int id)
{
return View();
}
althought int id is not used
You can't have multiple actions with the same name. You could add a parameter to one method and that would be valid. For example:
public ActionResult Index(int i)
{
Some Code--Some Code---Some Code
return View();
}
There are a few ways to do to have actions that differ only by request verb. My favorite and, I think, the easiest to implement is to use the AttributeRouting package. Once installed simply add an attribute to your method as follows:
[GET("Resources")]
public ActionResult Index()
{
return View();
}
[POST("Resources")]
public ActionResult Create()
{
return RedirectToAction("Index");
}
In the above example the methods have different names but the action name in both cases is "Resources". The only difference is the request verb.
The package can be installed using NuGet like this:
PM> Install-Package AttributeRouting
If you don't want the dependency on the AttributeRouting packages you could do this by writing a custom action selector attribute.
Today I was checking some resources about the same question and I got an example very interesting.
It is possible to call the same method by GET and POST protocol, but you need to overload the parameters like that:
#using (Ajax.BeginForm("Index", "MyController", ajaxOptions, new { #id = "form-consulta" }))
{
//code
}
The action:
[ActionName("Index")]
public async Task<ActionResult> IndexAsync(MyModel model)
{
//code
}
By default a method without explicit protocol is GET, but in that case there is a declared parameter which allows the method works like a POST.
When GET is executed the parameter does not matter, but when POST is executed the parameter is required on your request.

ASP.NET MVC - Overriding an action with differing parameters

I have a controller that inherits from a base controller. Both have an edit (post) action which take two arguments:
On Base controller:
[HttpPost]
public virtual ActionResult Edit(IdType id, FormCollection form)
And in the derived controller:
[HttpPost]
public ActionResult Edit(int id, SomeViewModel viewModel)
If I leave it like this I get an exception because there is an ambiguous call. However, I can't use override on the derived action, because the method signatures don't exactly match. Is there anything I can do here?
As addition to Developer Art's answer a workaround would be:
leave the base method as it is and in your derived class implement the base method and annotate it with [NonAction]
[NonAction]
public override ActionResult Edit(IdType id, FormCollection form)
{
// do nothing or throw exception
}
[HttpPost]
public ActionResult Edit(int id, SomeViewModel viewModel)
{
// your implementation
}
I'd chain it:
On Base controller:
[HttpPost]
public virtual ActionResult Edit(IdType id, FormCollection form)
And in the derived controller:
[HttpPost]
public virtual ActionResult Edit(IdType id, FormCollection form)
{
var newId = //some enum? transform
var boundModel = UpdateModel(new SomeViewModel(), form);
return Edit( newId, boundModel );
}
[HttpPost]
public ActionResult Edit(int id, SomeViewModel viewModel)
I haven't tested this, passing a Post method to another Post should work. There could be security implications this way.
That's all what you need to do
On Base controller :
adding virtual keyword
On Derived controller :
adding override keyword

Categories