RedirectToAction problem - asp.net-mvc

I have a Controller: AdminPageController, in which I have the following actions: Index, Create, Save
My save action is as follows:
public ActionResult Save(string[] inputs, int columnsCount)
{
.....
return RedirectToAction("Index");
}
I can see that the debugger passes throug the redurectToAction , but the index is not displayed. I can see that the routing is written as follows:
http://localhost:55405/AdminPage/Create#
What is wrong and how can I solve it?

Please use this utility displays the route data pulled from the request of the current request in the address bar. So you can type in various URLs in the address bar to see which route matches.
http://haacked.com/archive/2008/03/13/url-routing-debugger.aspx

Related

Attribute routing unexpected behavior on views outside specific action.

As an example I have two actions on one controller.
The actions both use attribute routing.
[Route("proofCampaign/{campaignId?}", Name ="Route1")]
public ActionResult ProofCampaign(int campaignId){
//Do stuff
return View{campaignVM}
}
[Route("proofOrder/{orderId}", Name ="Route2")]
public ActionResult ProofOrder(int orderId){
//Do stuff
return View{orderVM}
}
When I use #Url.RouteUrl("Route1") on any view I get the proper url but when I try to use #Url.RouteUrl("Route2") on any view I get a null.
However when I go to the actual page/view that Route2 leads to it returns the expected url.
The difference in the above code is the "?" in the route, even though the parameter is not optional.
Ultimately I want to display the second link on other views as part of a menu.
Why does the route not show up without putting in the optional param indicator?
Because orderId is not optional you need to include it in the Url
#Url.RouteUrl("Route2", new { orderId = xxx })

MVC 5: Obtaining the Refering URL

The controller class in MVC 5 apparently does not implement the Request.UrlReferrer as this property is always null and the VS says
When overridden in a derived class, get's information about the referrer URL ...
I check the ServerVariable and the Headers properties by serializing them as XML files to explore their contents and I did not found any key that returns the referring URL.
I already know how to manually handle this for example by TempData, Keeping the URL in session, ActionFilterAttribute for that. I'm not after any of these.
I simply wanna know if such behavior is implemented in MVC 5 by default and if so where I can find it.
The answers in other StackOverFlow posts are outdated
Request.UrlReferrer will give you a Uri object when you are visiting the current page from a link in another web page. If you are directly accessing the url ( as you do when you hit F5 button in Visual studio), you will get a null value as the return value of Request.UrlReferrer call as there we are directly going to this page.
To verify this you can do this.
Have 2 action method
public ActionResult Index()
{
var r = Request.UrlReferrer;
return View();
}
public ActionResult About()
{
return View();
}
Now in the about view(~/Views/Home/About.cshtml), add this makrup to generate a link to your index action.
#Html.ActionLink("Index","Index","Home")
Put a breakpoint in the Index action so you can inspect the r varibale value.
Run your app. Go to About page, Click on your Index link and see what value you get in the r variable when the breakpoint hits the Index action.

register and login in one page changes my url

Im having the following issue.
I have a View typed to a class SiteAuthenticationVM.cs.
The name of my view is "SiteAuthentication.cshtml" into the folder Views/Users
For other hand, i have one controller called UsersController with 4 actions:
[HttpGet]
public ActionResult Registration()
{
return View("SiteAuthentication");
}
[HttpPost]
public ActionResult Registration(SiteAuthenticationVM usertoregister)
{
return View("SiteAuthentication",usertoregister);
}
[HttpGet]
public ActionResult Login()
{
return View("SiteAuthentication");
}
[HttpPost]
public ActionResult Login(SiteAuthenticationVM usertologin)
{
return View("SiteAuthentication",usertoregister);
}
I have 2 routes defined:
"/register" is handled by UsersController Registration action.
"/login" is handled by UsersController Login action.
When i post my Login form is posted to /login if previously i was in url "/register", it changes to /login. Is there any way to keep my url "/register" for both post actions?
Is a bad practice if the url changes?
Your URL is denoting the controller method which is called, not whih View is being displayed. You can't change that, this is how MVC works. And your browser doesn't like to change its URL to 'B' if it needed 'A' to display that page, you cant really change it at rendertime.
Funny thing, if you had given your methods the same name, and had named your views differently, it would've worked without a hitch :-)
However, there are a few ways I can think of to get around this:
Give your methods the same name. This is the most straight-forward option. You can keep your View names, it's the method name that is important.
Make a method (e.g. "Switchboard") that calls either return View("Login") or return View("Register"). Your URL will contain "Switchboard" (you'll want a better name, but you get the idea).
Make the Login and Register pages into PartialViews. Display these in 1 View ("Switchboard", same name method). Then the URL will always denote the method ("Switchboard") you called for the View, not the PartialView.
Just remember, in MVC it's not about which View you are displaying, it's about which method you are calling.

How can I make an MVC POST return me to the previous page?

I have the following action which is called from a screen with a list of records.
[HttpPost]
//[Authorize(Roles = "admin")]
public ActionResult Edit(EditViewModel itemView)
{
Once the action has completed I would like to return to the page where the action was called from. However I don't want to refresh that page. I just want to go back to the populated screen using something similar to the "Previous" button in the browser. Right now when I click "save" my action does the following which is not what I want:
return RedirectToAction("Index");
Is there some way to Redirect to previous page with MVC3?
Something like the Stackoverflow functionality after I click edit to edit an answer where it returns to the post.
Instead of a redirection,
[HttpGet]
public ActionResult Index()
{
/// preform any processing necessary for your index page on GET
return View("Index");
}
[HttpPost]
public ActionResuit Edit(EditViewModel itemView)
{
if (ModelState.IsValid)
{
/// do whatever you want with your model...
}
// return the contents as they'd be rendered by the Index action
return Index();
}
Note that with this method the URL in the browser will still display the Edit url (like /area_name/edit), but you can fix that by:
Using a redirect (which you've said you don't want to do)
Using JavaScript to update the URL, or use history.back() as #AlanStephens suggested
Probably other methods that don't immediately come to mind.
However, I'd question whether this is really the best approach. Typically, users expect different URLs to do different things.
Or, if I understand you correctly and the edit action is being called from the Index page,
[HttpGet]
public ActionResult Index()
{
return View();
}
[HttpPost] /// from a form on Index
public ActionResult Index(EditViewModel model)
{
if (ModelState.IsValid)
{
////
}
return View();
}
and just take the /Edit out of play entirely. Again, I don't really care for this approach.
Based off the code you've given, it looks like you've got a paginated screen, with the ability to click edit on each row. Here's how I've solved this problem in the past.
On the Index page, when the page loads, whether it be from the main index or a paging method, add the following:
Session["CurrentUrl"] = Request.Url.ToString();
So now, at the end of the POST method for your edit page, do:
return Session["CurrentUrl"] == null ?
Index() :
Redirect(Session["CurrentUrl"]);
What you described is easily achieved using ajax calls. That way you perform whatever action you like and afterwards (on successful response), you can easily navigate from the current page, using javascript.
If you POST to a page and in response you return the same view you receive with a GET request (index page), then some users might hit F5 to reload that index page and get a warning in the browser, which actually says it will send the POST request again. This is pretty confusing for users and not really user friendly (not to mention numerous concerns related to idem-potency of it).
Although you don't like the redirect approach, because of the additional response, I guess, I should say that, in MVC, this is the correct way to do it, assuming you don't want to use ajax calls.

Asp Net Core 2.2 on random address goes to controller instead of 404 Not Found

If the address is well formatted everything is fine.
But when I type random string into the address bar, asp net core routes to the same controller and in particular to Index(model)
[HttpGet]
public IActionResult Index() { ... }
[HttpGet({model})]
public IActionResult Index(ViewModel model) { ... }
instead of returning 404 Not found.
Is the problem with the controller?
Your HomeController is mapped to "" or the empty route, and then this second Index action requires basically any route portion. So, /foobar literally routes to this Index action.
There's a number of problems/misunderstandings here. When you specify {model} in the route, you're telling the framework that this is a route param. There's effectively no way to actually ever bind your model, because you can't actually post a representation of ViewModel within a route path.
Second, there is no validation of route params during routing. In other words, ASP.NET Core doesn't look at you action, see that it needs to be an instance of ViewModel, realize that foobar in /foobar is not a ViewModel and then returns 404. It merely sees that there's a potential route that takes something in that route segment, and then attempts to load up the corresponding action. It's on the modelbinding phase where things will fail, but that's after the routing is already done.
You can use route constraints to add a layer of validation. For example, {foo:int} would only match if the value in that route segment was something that could be cast to an int, but you can't really do that for something like ViewModel.
Third, you shouldn't be sending an entire model via a GET. GET doesn't have a body, and complex objects should go in the body of the request. You should be using POST here instead.
Long and short, change your action to:
[HttpPost]
public IActionResult Index(ViewModel model) { ... }
And you'll be fine.

Resources