Attribute routing unexpected behavior on views outside specific action. - asp.net-mvc

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 })

Related

Reload page but get a 404 error because of wrong url when routing in MVC

My View is called Survey.cshtml. My current url is http://localhost:17471/Campaign/Survey/6184.
In this page I have a drop down menu to select language. There are English and Spanish. One I select the language, I want to reload the page because some context are shown in different language. I still want to keep the same url.
My code in Survey.cshtml.
$("#id").change(function () {
var selectedValue = $(this).find('option:selected').text();
window.location.href = "#Url.Action("Survey1", "Campaign", new {id=Model.SurveyModel.CampaignId, languageName = "languageToken" })".replace("languageToken", selectedValue);
});
However it goes to the url http://localhost:17471/Campaign/Survey1/6184?languageName=Spanish
My controller CampaignController.cs has the methods.
public ActionResult Survey(int id)
{
// omitted code
return View(model);
}
[HttpPost]
public ActionResult Survey1(int id, string languageName)
{
// omitted here
var view = "Survey";
return View(view,model);
}
I don't have Route for the above methods in RouteConfig.cs. I am not very strong on MVC Routing. Sometimes I am confused the old-and-good HTTP URL ENCODING with the http://site-address/page.html?param1=value1&param2=value2 and the MVC ROUTING which uses the form of http://site-address/page/value1/value2.
So help me.
Your Survey1 action is decorated with [HttpPost], which means you have to use the POST method from your client. But when you do a redirect with window.location.href, that always uses the GET method. You have two options:
Change your controller action and remove [HttpPost].
Create a form with the POST method and your values in it, and use javascript to trigger the submit event on that form instead of using window.location.href.

MVC catch all route passing URL

I have a decent size MVC 4 app that is making heavy use of Areas, plus the basic Home and Account controller. What I need to do is have a URL pattern that goes to a Controller and passing the rest of the URL. I've tried just about every combination, but nothing seems to be working.
I created a controller called AutoInController with the following method:
[AllowAnonymous]
public ActionResult Index(string url)
{
string mes = string.Empty;
return View();
}
And I want to pass any URLs requested, starting with 'AutoIn' to this method with the rest of the url as the parameter. Here's the route I've tried, along with various others including using constraints. I'm adding this last, after the default.
routes.MapRoute(
"Autologin",
"AutoIn/{*url}",
new { controller = "AutoIn", action = "Index" }
);
Any ideas what I'm doing wrong. It shouldn't be this hard. Thanks.
I tried just about everything and the problem was that I couldn't get it to catch all that prefixed with 'AutoIn', just ALL.
I ended up changing my AccountController to handle this on the Login method to interrogate the URL and then if it was prefixed with 'AutoIn', take appropriate action.
Thanks for the answers. Routes can be tricky when you want to do some special stuff.

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.

ASP.Net MVC Route not passing parameter to controller

I'm trying to learn MVC and having a rough start.
routes.MapRoute(
"Test",
"Test/{stringInput}",
new { controller = "Test", action = "TestMethod", stringInput = "" }
);
doesn't pass stringInput to the method TestMethod in the controller. It comes over null.
Not sure what I'm missing, it seems very simple and straightforward. This route was placed above the default.
Override the Execute method of your controller and then put a breakpoint in it so you can see the request context. One of the properties is the key/value pair being passed in. Make sure the key for stringInput has the correct value.
Make sure your controller is setup properly. It should be in folder
Controllers/TestController.cs
and inside the controller should be
public ActionResult TestMethod( string stringInput )
{
return View();
}
It uses conventions, so the naming you setup in your route needs to match the files, methods, and parameters of the controller.
The url to get to this should be
/Test/TestMethod/MyStringInput
and "MyStringInput" would be the value of the variable stringInput.
Are you sure that route is the one being used? Try moving it to the top of your list of routes to make sure.

In ASP.NET MVC, preserve URL when return RedirectToAction

I have an action method, and depending on what is passed to it, I want to redirect to another action in another controller. The action and controller names are determined at run time.
If I return RedirectToAction(), it will force a redirect and change the URL in the browser. What I would like is something like TransferToAction() that can transfer processing of the current request to another action, without doing a redirect. I seem to remember a method behaving like this in earlier previews, but I can't seem to find it in the RC of ASP.NET MVC.
Do you know how I would do this?
UPDATE
I added the following route:
routes.MapRoute(
"PageRouter",
"{site}/{*url}",
new { controller = "PageRouter",
action = "RoutePage", site = "", url = "" }
);
And the PageRouter controller action RoutePage:
public ActionResult RoutePage(string site, string url)
{
var controller = new HomeController {ControllerContext = ControllerContext};
controller.RouteData.Values["controller"] = "Home";
controller.RouteData.Values["action"] = "Index";
return controller.Index(site, url);
}
I had to set the controller and action in RouteData for the Home Index view to be rendered. Otherwise, it would look for an Index view in PageRouterController.
I still need to figure out how to create a controller and its action knowing only their names. e.g. I'd like to be able to just call something like this:
public ActionResult RoutePage(string site, string url)
{
return InvokeAction("Home", "Index");
}
What should go in InvokeAction() ? Do I need to pass it any context?
You should be able to just call the other method directly and, assuming that it returns a ViewResult, it will render that view in response to the request and the url will not change. Note, you'll be responsible for making sure that all of the data that the other method needs is available to it. For example if your other method requires some form parameters that weren't provided, you may need to construct a suitable FormCollection and set the ValueProvider of the controller to a ValueProvider based on your FormCollection. Likewise with any arguments required by the method.

Resources