Modify Request to a POST - asp.net-mvc

I have an MVC 2 app and is getting errors when I try to redirect to the following method;
[ValidateAntiForgeryToken]
[Transaction]
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(Payment payment, PaymentApplication paymentApplication, string exchangeId, bool manual, int firstPaymentId, int? exchangeEventId, bool addOnly)
{
because it has POST property. Is there anyway I can modify the request header to 'simulate' a POST and go to the correct action??

No, you cannot redirect to actions that require POST verb. Redirects are performed by the client browser using GET verb after the server sent a 301 status code to the new location.

Related

Why is my routing prefix not working?

In my browser's address bar, I've got the following input:
http://localhost:55105/Tasks/UpdateStatus/8/1
However, it is not hitting my controller method when I debug.
[Route("Tasks/UpdateStatus/{id}/{status}")]
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult UpdateStatus(int id, int status)
{
Task task = db.Tasks.Find(id);
if (ModelState.IsValid)
{
task.Status = status;
db.Entry(task).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(task);
}
Getting following error:
Server Error in '/' Application. The resource cannot be found.
Your action method expects the parameters to be passed as POST and the via the way you are doing in the browser url it is get request as parameters are part of url as query string. What you need is a form in your view and post the values via form.
Make sure that you are sending the data as post method for you request.
For just to understand you can try renaming the [HttpPost] to [HttpGet] and see it will work, but that's not the way for the above use case as you are updating data in database so you should be using POST not GET

FormAuthentication with WebAPI using Breeze

I am protecting WebAPI using forms Authentication, that is using Breezecontroller
When i try to call WebAPi method i am getting back the following error.
status:404
statusText: "Not Found"
message:"MetaData query failed for:'';, No Http resource was found tha matches...
My question is why am i not getting back "UnAuthorized error(401)" ?
metadata is decorated with [Authorize] as well.
Seems like FormsAuthentication's redirect is giving problem.
It is redirecting to Login(has AllowAnonymous) WebApi method and reports it cannot find, eventhough i have. Also i am applying the Authrozie to the methods instead of controller. the exact error is
{"$id":"1","$type":"System.Web.Http.HttpError,System.Web.Http","Message":"NoHTTPresourcewasfoundthatmatchestherequestURI'http://localhost:40678/api/Country/Login?ReturnUrl=/api/Country/Metadata'.","MessageDetail":"Noactionwasfoundonthecontroller'Country'thatmatchestherequest."}
Just tried and working fine. I'm betting you have a mistake in your URL.
Here is the prelim to my controller:
[Authorize]
[BreezeController]
public class BreezeTodoController : ApiController
{
private readonly BreezeTodoContext _context;
public BreezeTodoController() {
_context = new BreezeTodoContext(User);
}
[HttpGet]
public string Metadata() {
return _context.Metadata();
}
// ... more
I hit it with this URL
http://localhost:32377/api/breezetodox/metadata
And I get back the 401
Request URL:http://localhost:32377/api/breezetodo/metadata
Request Method:GET
Status Code:401 Unauthorized
But if I make a mistake in the URL (see 'x' after breezetodo)
Request URL:http://localhost:32377/api/breezetodox/metadata
Request Method:GET
Status Code:404 Not Found
Same thing if my action name doesn't match (see 'x' after metadata):
Request URL:http://localhost:32377/api/breezetodo/metadatax
Request Method:GET
Status Code:404 Not Found
In other words, HTTP can't report that a resource is unauthorized if it can't find that resource in the first place.
when tagging the BreezeController with [Authorize] and then trying to retrieve the Breeze Metadata directly with this link:
Request URL:http://localhost/breeze/breeze/metadata
redirects to:
http://localhost/Login?ReturnUrl=%2Fbreeze%2Fbreeze%2Fmetadata with a 404
Without the [Authorize] the access to the Breeze metadata with the same link works fine.

RedirectToAction is not redirecting at all

i'm using RedirectToAction to redirect after a post to another controller and it's working. so i tried to Redirect to another action in the same controller and it's NOT working too.
public ActionResult finalize(int id)
{
Meeting meeting = db.Meetings.Find(id);
meeting.meetingStatus = "finalized";
db.SaveChanges();
return RedirectToAction("Index");
}
public ActionResult Create()
{
return View();
}
[HttpPost]
public ActionResult Create(Meeting meeting)
{
if (ModelState.IsValid)
{
db.Meetings.Add(meeting);
db.SaveChanges();
// return RedirectToAction("Invitation");
return (RedirectToAction("finalize", new { id = meeting.meetingID}));
}
return View(meeting);
}
you cant make 2 redirects in the same call , a redirect just return an http redirect code to another page , redirecting 2 times just wont work, don't treat action methods like normal methods they are different
for example when you request a page example.com/controller/action
action will be executed and for example it has a return value with RedirectToAction("NotFound")
what will happen in this scenario is
action body will be executed and the return value will send to the client an http header of 302 that says your new destination is /controller/NotFound
so RedirectToAction just return an http code to the client its not calling another method
Update
i was wrong i checked with fiddler2 , you can use redirect to action many times , what will happen the server will send multiple http redirect headers for each one
i jumped to conclusion this fast because i didnt think multiple redirect is the right way to do it, so after i tried it , i can say it works , just create a new project to see where is the problem exactly or use a tool like fiddler2

ASP MVC: ActionFilter attribute -> RedirectToRouteResult always redirect to HTTP GET

I have an ActionFilter attribute at the top of my controller.
[HandleError]
[MyActionFilter]
public class AccountController : Controller
{
...
}
When an action is received, i want to add/change some route values and then redirect to a correct route.
filterContext.Result = new RedirectToRouteResult(new System.Web.Routing.RouteValueDictionary(new { lang = langName, controller = controllerName, action = actionName, id = idName }));
This is working fine. However, the redirection is always set to HTTP GET, and since some of my actions are set to receive only HTTP POST, it fails.
Is there any way to make the redirection be HTTP POST?
Is there any way to make the redirection be HTTP POST?
No. The verb GET is at the very base of the definition of a redirect in the HTTP specification. It simply doesn't make sense to talk about an HTTP redirect and an HTTP verb different than GET.
Instead of redirecting you could return a view directly:
var result = new ViewResult
{
ViewName = "~/Views/Shared/SomeView.cshtml",
};
result.Model = new MyViewModel();
filterContext.Result = result;
As you said, you are redirecting your users to another action. This in HTTP protocol means that you send codes 301, 302, or 303 alongside your response to clients' browser.
Browser on the other hand always sends an HTTP Get in reaction to an HTTP redirection.
Thus, your answer is:
No

What is the correct response to an HTTP POST request?

For a POST method, the W3 specs say:
If a resource has been created on the origin server, the response
SHOULD be 201 (Created) and contain an entity which describes the
status of the request and refers to the new resource, and a Location
header (see Section 10.4).
http://www.ietf.org/internet-drafts/draft-ietf-httpbis-p2-semantics-05.txt (section 8.5)
The standard response actually seems to be to send a Redirect to the newly created resource.
I'm building my site with ASP.NET MVC, and tried to follow the spec, so created a ResourceCreatedResult class:
public class ResourceCreatedResult : ActionResult
{
public string Location { get; set; }
public override void ExecuteResult(ControllerContext context)
{
context.HttpContext.Response.Clear();
context.HttpContext.Response.StatusCode = 201;
context.HttpContext.Response.ClearHeaders();
context.HttpContext.Response.AddHeader("Location", Location);
}
}
And my action looks something like this:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult CreateNew(string entityStuff)
{
Entity newEntity = new Entity(entityStuff);
IEntityRepository entityRepository = ObjectFactory.GetInstance<IEntityRepository>();
entityRepository.Add(newEntity);
ActionResult result = new ResourceCreatedResult()
{ Location = Url.Action("Show", new { id = newEntity.Id }) };
return result;
}
However, IE, Firefox and Chrome all fail to redirect to the new resource. Have I messed up generating the correct response, or do web browsers not expect this type of response, instead relying on servers to send a Redirect response?
To be explicit, browsers (including modern browsers like Firefox 3 and IE8) do not "take the hint" and follow up an HTTP 201: Created response with a GET request to the URI supplied in the Location header.
If you want browsers to go to the URI supplied in the Location header, you should send an HTTP 303: See Other status instead.
Redirect after post or post/redirect/get is something your application must do to be user friendly.
Edit. This is above and beyond the HTTP specifications. If we simply return a 201 after a POST, the browser back button behaves badly.
Note that Web Services requests (which do NOT respond to a browser) follow the standard completely and do NOT redirect after post.
It works like this.
The browser POSTS the data.
Your application validates the data. If it's invalid, you respond with the form so they can fix it and POST.
Your application responds with a redirect.
The browser gets the redirect and does a GET.
Your application sees the GET and responds.
Now -- hey presto! -- the back button works.
My solution is to respond with a '201 Created' containing a simple page with a link to the new resource, and a javascript redirect using location.replace().
This lets the same code work for API and browser requests, plays nicely with Back and Refresh buttons, and degrades gracefully in old browsers.
As stated in the spec the response SHOULD be a HTTP 201 with redirect. So it isn't mandatory for a browser vendor to implement the correct answer...
You should try to change to a 30x code to see if it is correctly redirected. If so, it's a browser problem, else it may come from your code (I don't know anything in ASP.NET so I can't "validate" your code)
Shouldn't that only count for when something is "Created" and therefore a simple redirect to action should be genuinely sufficient?

Resources