If I have 2 controller actions:
[HttpGet]
public ActionResult Login()
{
//...
return View();
}
and
[HttpPost]
public ActionResult Login(FormCollection values)
{
//...
return RedirectToAction("Index","Home");
}
It seems that the Post decoration is required for this to work (which makes sense), but the HttpGet decoration is entirely optional. It works fine with or without. It seems that MVC defaults controller actions to HttpGet unless otherwise specified.
I'll have to decided if I want a future reader of my code to have to figure that out on my own or not, or whether I want to have to remember to add HttpGet everywhere for consistency. But my question is not about whether it is a good practice to include the explicit decoration even though it is defaulted that way already.
My question is: is it ALWAYS the case that I don't need to decorate controller methods with HttpGet? Is there some way that this can bite me if I do or do not explicitly specify? I've searched on this a but and all I can find is posts describing why you might want to use both annotations rather than the reason for/against including the HttpGet specifically.
You don't have to specify this explicitly, no. However, please note:
Not specifying the verb on an action will mean that the method accepts both GET and POST. If there are two actions, however, the one labelled POST will be used for POST and the other will default for GETs.
Applying HttpGet will mean an action accepts only GET requests.
Labelling actions as GET can make it more obvious to other developers what your intention is.
Is there some way that this can bite me if I do or do not explicitly specify?
Not very likely. I could imagine a situation where something might be showing some strange behaviour or not working as expected because of it, but it'd be rare.
Is there some way that this can bite me if I do or do not explicitly specify?
Here I want to develop an answer of Rowan Freeman about the consequences of not using [HttpGet] explicitly for every GET method.
As it was already mentioned, a method without [HttpGet] annotation will accept both GET and POST request (unless there is another method with same name that is annotated with [HttpPost]). If a method is explicitly annotated with [HttpGet], 405 Method Not Allowed will be returned.
One consequence that I could imagine is that if an attacker wanted to send big amount of data through GET request, it would have a limit. Without [HttpGet] annotation, this limit is not a problem, because an attacker can switch to POST and do the same without any limit.
Another similar case is that:
HTTPGet can carry only string data whereas HTTPPost can carry both string and binary data.
Yet another thing is that POST requests will probably not entirely be logged on a server, therefore an attacker can somehow hide it's activity from an administrator as attackers payloads won't be visible (body won't be present in logs).
A comparison between POST and GET (which I cited from) can be found here:
ASP.NET MVC 5 – HTTPGET And HTTPPOST Method With Example
Of course, all of these cases are pretty rare, but this is what exploiting is about - finding rare things that can turn out to be a vulnerability.
To conclude, it is a good habit to always write [HttpGet] annotation in controller methods. It is just a one line that can improve security of your web application.
Related
As far as I understand the ApiController is for performing CRUD on resources.. But I have a case where I am just calling some Helper method (Restoring a DB on a SQL server) and so I am not sure if ApiController makes sense ?
Should I only use ApiController when I am performing CRUD on something ? Or should I use ApiController for anything that does not return a view ? Is 'post' the correct HTTP verb to use ? Am I going about this all wrong ?
Id like to get it clear in my head when to use one over the other.
[HttpPost]
public JsonResult RestoreBaselineDB()
{
//Get values from web.config
string sqlServer = ConfigurationManager.AppSettings["DBTools_sqlServer"];
string backupFilePath = ConfigurationManager.AppSettings["DBTools_backupFilePath"];
string destinationDatabaseName = ConfigurationManager.AppSettings["DBTools_destinationDatabaseName"];
DatabaseHelper.RestoreDatabase(sqlServer,
backupFilePath,
destinationDatabaseName,
"c:\\temp",
"ProcessManager",
"ProcessManager_log");
return Json(new
{
Status = "OK",
}, JsonRequestBehavior.AllowGet);
}
Controller is the base class for MVC, and ApiController for web api, which can be intermixed but should have clear, distinct purposes. I would use ApiController if you intend to create a restful web service, and Controller for your web application's user interface. I wouldn't necessarily intermix the two, based on the function you are creating.
For instance, if you are creating a REST service for an API your are exposing to the world or your application, keep everything contained in a web api set of APIControllers. But consider using a Controller for returning JSON to a view in a utility scenario.
This is, of course, subjective and likely to have differing opinions.
As #Brian Mains recommends, in your situation, you should use an ApiController because, as you say, it does not return a view. Controller should be used for your UI.
The answer to your question about is ApiController just for CRUD takes you dangerously close to the REST flame wars.
A pure REST approach to this would be to think of your restore database operation as creating a DatabaseRestoreRequest resource (and therefore should be a POST).
POST <Host>/Api/DatabaseRestoreRequest
Since the restore is probably a lengthy operation (especially for large databases), the body of the POST response would represent a resource with a unique identifier and a status that could be one of
InProgress
Failed
Complete
Having done a POST to initiate the restore (status would be InProgress), you would then make a GET request, providing the unique identifier. The GET response would give the updated status. You could call GET repeatedly until the response had a status of Complete.
GET <Host>/Api/DatabaseRestoreRequest/<requestID>
You may also have a DELETE operation, which could cancel the restore operation.
DELETE <Host>/Api/DatabaseRestoreRequest/<requestID>
If this seems over complicated and unnatural to you, you could just use a pattern like that used by the Windows Azure management API (and others). This uses a URI scheme that indicates a resource in the main URI and then the operation as a query string parameter
For example, to re-image a virtual machine you would do a POST to
https://management.core.windows.net/<subscription-id>/services/hostedservices/<cloudservice-name>/deploymentslots/<deployment-slot>/roleinstances/<role-instance-name>?comp=reimage
In your case it could be something like
POST <Host>/Api/Database?comp=restore
POST is traditionally used for this kind of operation because they are often non-idempotent. Idempotent means that if you repeat it several times it has the same effect as if you do it just once). PUT is supposed to be idempotent. POST does not have to be. This comes from the W3C:
http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html
REST purists might decide to flame and downvote me for suggesting the second option. But hey...
When I use RedirectToAction("MyView", "MyController") sometimes the redirection is very slow to render the destination view.
It doesn't always happen.
I am using ASP.net MVC4 with IIS7.5
How can I prevent this problem and speed up the redirection?
I will put this here as code will not show very well in the comments section. If the action method you are redirecting to is in the same controller you are currently in, it is simpler and more efficient to call that method directly and return its results instead of the redirect response generated by the RedirectToAction method. Just to make sure we are on the same page, RedirectToAction actually returns a redirect response (302) to the client asking it to issue a new request to the action method you have specified as per MSDN http://msdn.microsoft.com/en-us/library/system.web.mvc.controller.redirecttoaction(v=vs.108).aspx. Some code to illustrate:
public ActionResult MyAction(){
//do some work here
Return View(MyModel);
}
public ActionResult ActionIAmCurrentlyIn(){
//Do Soe work here
return RedirectToAction ("MyAction", "MyController"); //This costs an extra trip across the wire
return MyAction(); // Does same thing but without the extra trip to the client
}
This overhead of the extra trip becomes more significant if there are parameters being passed along to "MyAction" and as the network speed goes down.
Responding as an answer because I don't have enough rep to add a comment...
#JTMon In your code the "return MyAction();" can cause potential issues because the "MyAction" action will actually try to load a view named "ActionIAmCurrentlyIn" since that is the action that's specified in the route values (at least I assume that's where it's getting it from, I haven't actually dug into the code to find out).
This can be resolved by specifying the view name in MyAction:
return view("MyAction", MyModel);
To prevent this problem and speed up the redirection use:
return Redirect("~/MyController/MyView");
This approach will not change client-server interaction.
You can use RedirectToActionPermanent("View","Controller"); for it.
I want to pass a class object from one controller action to different controller's action.
Sender Action
public class CourseController : Controller
{
[HttpPost]
public ActionResult CreateNewCourse(CourseViewModelBase courseViewModel)
{
if (ModelState.IsValid)
{
// Do some stuff
return RedirectToAction("CreateNewProject", "Project",
new { courseVM = courseViewModel});
}
// Bad happened
return View("CreateNewCourse", courseViewModel);
}
Receiver Action
public class ProjectController : Controller
{
[HttpGet]
public ActionResult CreateNewProject(CourseViewModelBase courseVM)
{
// Use CourseVM data and do other stuff
return View("Create", projectCreateViewModel);
}
}
I am getting data properly in Sender Action and Receiver Action is called properly from the redirect to action call. However courseVM in Receiver Action is null.
I know this is a very old question and had been asked repetitively. But I found that most of the answers suggested to use TempData and were answered in 2008/2009. I believe there would be someway to pass data using RedirectToAction without using TempData. If there is not then I would go with TempData only.
Finding
If I pass some simple data e.g. new {id = courseViewModel.CourseDuration} and change the argument in Receiver action to id then id is properly received.
Similar Questions
Question 1
Question 2
Question 3
Question 4
Question 5
Question 6, tried to use this one but did not workout
Question 7
Question 8
Question 9
Question 10
Most of the answers in above questions are dated back in 2008/09 and uses tempdata.
This question itself is now about a year old, but I came across it so I thought I would help out others who come across it in the future. The accepted answer doesn't work - the complex object still arrives at the receiving action null.
I found that this answer from 2012 is still valid. You just can't pass complex objects in an HttpGet request (by nature this is what a RedirectToAction is - again, not something you can change). You can only pass scalar values: int, string, etc.
Make sure you've ruled out the below two options:
Avoid sending a complex object altogether, and send only scalar values. Obviously this is only an option sometimes - but I mention it as a reminder to consider it.
Skip the receiving Get action altogether - perform its logic & return the View directly from your Post action. Ie; return View("ReceivingViewName", viewmodel) Again, will only work for some situations, more than likely you'll need the other action and thus will need the Redirect, but worth remembering as a possiblity.
If you can't get around the problem, and have eliminated the two above options, your options are:
Persist the data to Database, possibly using a temp table if you know the data won't be used later. Send the primary key to the receiving action, and once there, query the database. This is the "cleanest" option.
[Edited Option] Store the object in TempData (data lasts only thru the next request in which it is used - if it's not used, it will hang around for the life of session) or Session (data lasts for life of session). Neither are really great options. TempData is probably the better of the two, as its lifespan is potentially shorter... but you'll still have to consider what happens when a page reload occurs or a subsequent request is made to the method (WebGrid paging, for example - which was my scenario). For these specific scenarios, I originally recommended getting the data out of TempData, and then putting it back in so it's available for a subsequent request to that action. Since TempData actually hangs around until it's used once, that makes this option even less desirable, since it won't go away if the user navigates elsewhere. More info on this in the answers here. Bottom line is don't put anything in TempData unless you intend to use it right away. If you don't need the data for a specific scenario like paging, and you put it in TempData and immediately consume it in the receiving method, without putting it back in, this option is okay. The first option is still better.
use this
return RedirectToAction("ActionName", "ControllerName", modelObj);
in your case
return RedirectToAction("CreateNewProject", "Course", courseViewModel);
You can also use
TempData
Those who have read about CQS principle know that:
CQS states that every method should
either be a command that performs an
action, or a query that returns data
to the caller, but not both.
Speaking of ASP.NET MVC Actions, does CQS indicate that we shouldn't have an Action like this?
public PartialView InsertOrder(Order order)
{
OrderService.InsertOrder(order);
return PartialView("OrderDetails", order);
}
This method is changing the state of the system and returning the current state. If CQS is applied here, we should have 2 separate Actions: one for inserting a new order and one for getting the system of the system (which should be called from the client if the first Action was completed successfully). However, this complicates programming.
I'd like to know your opinions on this.
Mosh
A common example of Command/Query Separation on the web is Post/Redirect/Get.
In ASP.NET MVC, this is usually implemented in the simplest way as
[HttpPost]
public ActionResult UpdateOrder(Order order){
UpdateOrder(order);
return RedirectToAction("ViewOrder", new { order.OrderId });
}
[HttpGet]
public ActionResult ViewOrder(int orderId){
return View(GetOrder(orderId));
}
For AJAX, and a partial view, this might not be the best strategy, since the problems that Post/Redirect/Get solves aren't really relevant, and the redirect can be tricky.
CQS is only concerned with command and queries to the same object. Since a OrderView the Order are not the same object (I guess from your implementation) the principle does not apply, so your code is not counter the principle neither in favor :)
I've never heard of CQS, but if you are doing ASP.NET MVC (MVC pattern) the action you wrote is perfectly fine (assuming this OrderService there is an abstraction to the real service). The controller manipulates the model and decides which view to render and passes this model to the view.
I had a vague recollection of this term from the eiffel days (which if followed all the way back, actually predates most current oop principles by a good decade or so (late 80's i think). I'd suggest that this term and/or principle may well be outmoded now and superceded by actionresults in mvc (be that asp or codeignitor etc, etc). I actually think that in terms of the definition (which i just looked up now), this separation is concerned with the logic that performs the action i.e. OrderService.InsertOrder(order) in your example. So, in a way, mvc as performed in your action is actually loosley following this pattern (InsertOrder doesn't attempt to present any stateful info, purely process the order object).
I'd suggest that you look at best practice for asp.net mvc which is fundementally based on returning an actionresult (or partial, contentresult etc, etc). this pattern was designed to simplify the paradigm to facilitate productivity in a uniform and universally accepted fashion.
of course, you could use your action return values to generate a success or fail for the insert/update/delete scenarios and then request partial views based on those return value. However, i personally don't think i'd leverage too much value from that approach bearing in mind the fact that the controller in MVC is concerned with stearing the logic of which view should be returned as the result of an action.
hope this helps
jim
I'm writing a new asp.net mvc application and I've been toying with the idea of allowing my user to post short, concise urls to content that he has posted. Those short url's will be handy in cramped spaces like Twitter and comment areas. I like this idea as I'm not a huge fan of url shorteners because they're so vague and you're never really sure what you're going to get. Instead of using a url shortener I want to give my client the ability to post:
http://domain.com/p/234
which does a 301 redirect to:
http://domain.com/2009/08/10/this-is-the-content-title
Now, this is a pretty simple process with a couple of extra routes and a custom ActionResult. The custom ActionResult I implemented is an extension method on a RedirectToRouteResult... It's fairly straightforward but about 20 lines of code nonetheless. I played around with doing the same functionality, only this time with an ActionFilter. My action filter looks like:
public class PermanentRedirectAttribute : ActionFilterAttribute
{
public override void OnResultExecuted(ResultExecutedContext filterContext)
{
filterContext.HttpContext.Response.StatusCode = 301;
}
}
and my action method looks like (I removed a bunch of code to simplify):
[PermanentRedirect]
public ActionResult ShortUrl(int id)
{
return RedirectToAction("Post", id);
}
My question is this: Did I miss something or is it this simple? I've found some other posts where people are looking to do something similar and they always create a custom ActionResult. Besides using less overall code, given that this behavior may need to be used elsewhere on other action methods, I don't see why it shouldn't be an ActionFilter. With that being said I'm fairly new to the Request and Response objects so I'm not sure if I'm missing something.
The code you have shown will work just fine. However, I recommend using a custom action result instead of using an action filter.
One reason for this is that it will provide more information for your unit tests since there are fewer things to verify. That is, with a custom action result you can verify that the right type of result was used and that it has the right properties set on it. With your current design you'd have to separately verify both the action result data and that you correctly applied the attribute.
Another reason is that the code will be cleaner: There will be fewer things for other developers (or you in 2 weeks) to look at or understand. Looking at a simple return PermanentRedirectToAction("Post", id) is much easier than looking at an attribute and the return data.