Asp mvc redirect without affecting url - asp.net-mvc

I have a rather archaic login system, and this is part of the login action:
// login action
return RedirectToAction("Action", new {
id = aVal,
name = aName,
// other params
});
It redirects the user to the Action action, and i noticed that name and the other params ended up being part of the final url scheme. I need to pass all those values to Action.
[HttpGet]
public ActionResult Action(int id, string name, ...) {
Is it possible to pass them to Action and having the url like this: /Controller/Action/123.
I need to restrict the Action method to only those who pass through the login action, the long url + query string make it almost impossible to make it through, but is there another more profesional way to do it.
Thanks and greetings to the SO and SE community.

In order to get Restful styled url's you need to setup an appropriate route.
So in your case something like
routes.MapRoute("MyRoute", "MyController/MyAction/{id}/{name}", new { controller = "MyController", action = "MyAction" });
you can see some other examples here
The second part of your question is more vague - you may want to tag your class with an [Authorize] attribute and then override OnAuthorization where you can do any checks. Not sure if this is what you are looking for.
There is an example of this here

Related

How can I extract a parameter named "action" from the url without having to manually parse the querystring in MVC?

I have a site entry controller that is used via a url generated by a single sign on manager. The SSO manager appends an identifying hash as an action parameter to the url of the system it is attempting to sign on to.
So the url being generated by the SSO manager looks like:
http://mysite/Entry/SingleSignOn?action=123456789ABCDEFG
I think I just need to set up a better route, but I haven't been able to get it to work yet. When I try to get the action from the url via standard MVC binding, it is giving me the name of the action, not the hash I need:
public ActionResult SingleSignOn(string action)
{
// action returns "SingleSignOn"
var querystring = Request.Url.Query; //returns "?action=123456789ABCDEFG"
return RedirectToAction("Index");
}
I know I can just split open the querystring, but would prefer not to if possible. It doesn't seem like a terribly complex problem, but I am just not finding the right route.
You can use Request.QueryString["action"] to explicitly get the parameter value from your request url.
public ActionResult SingleSignOn(string action)
{
var querystring = Request.QueryString["action"];
// Do something with querystring
return RedirectToAction("Index");
}

How to rewrite MVC 5 routes?

I have two question about generating routes in MVC 5.
This is example:
routes.MapRoute(
name: "ActionSite",
url: "{userName}/sites/{action}/{localSiteName}",
defaults: new { controller = "Site" }
);
#Url.RouteUrl("ActionSite", new { action="Edit", siteOrder = site.Order, localSiteName = site.LocalName, userName = ViewBag.UserName })
generates the next url:
https://localhost:44344/TestUser/sites/Edit/Site2?siteOrder=1
1)How to hide variables? I want to hide: ?siteOrder=1
2)TestUser is userName. At this moment I set manually it in all [Authorize] actions. Can I do this one time in some special method?
About first question, RouteUrl assumes you are going to use the URL in a GET method and when you are using GET verb you have to append query string to the URL. siteOrder has to be in query because you did not put it into URL template. Any extra parameter goes into query string.
Solution here is to use POST instead of GET. Down side would be losing simple GET calls ( anchor) from client side. You have to use #Html.BeginForm instead of #Html.ActionLink.
Second question is not clear, if you generate URL like https://localhost:44344/TestUser/sites/Edit/Site2?siteOrder=1 then you will get username form URL.
for example:
public ActionResult Edit(string userName, string localSiteName){ }
username here will be "TestUser" and you have to check authentication if userName is same as User.Identity.GetUserName()
Or you can write AuthenticationFilter to do the authentication job for you.
But if you mean a way that Url.RouteUrl automatically fill in userName property based on User.Identity I think answer is no. You have to retrieve username somewhere in ActionFilters or in Action or if you are using ASP.Identity then you already have the user name all the way down to the View, just you need to call
#User.Identity.GetUserName()
in your View or Controller to get it.

How to have POST ActionHandler return the GET ActionHandler by a custom Attribute?

Our system is MVC2 authenticated by ADFS 2. So when a user clicks on a bookmark for http://www.foo.com/Car/Details/3, this hits our Car controller and calls our Details GET action handler and passes 3 in as the ID (all basic MVC stuff). So we have this ActionHandler decorated with a [Authorize] attribute and have ADFS2 hooked up, so the page then redirects to our auth server which then redirects back to our app, but with a POST (all basic ADFS stuff). The problem is that this redirect is a POST and therefore our Details POST handler is called, but clearly it doesn't have the data I need.
Now I have identified some code that detects this scenario and this code looks something like this:
[Authorize]
[MySpecialHttpGet]
public ActionResult Details(long id)
{
var model = GetModel(id);
return View(model);
}
[Authorize]
[MySpecialHttpPost]
public ActionResult Details(long id, ViewModel model)
{
/***START OF SPECIAL CODE***/
// If we were posted to by ADFS, redirect to the GET handler.
if (Request.Form["wa"] != null && Request.Form["wa"].ToLower().Contains("signin"))
{
// We were posted to here but need to respond with the GET view.
return Redirect(Request.Url.AbsoluteUri);
}
/***END OF SPECIAL CODE***/
var result = Something.SaveData(model);
return result.ActionResultToReturnWith;
}
The problem with this is that I need to do this on every single POST ActionHandler in the app and I really don't want to do that. Given that I already have custom attributes on all of these ActionHandlers, I would like to use those attributes to inject this functionality for me.
Now the MySpecialHttpGet and MySpecialHttpPost are nothing incredibly special that you really need to know about other than they extend ActionMethodSelectorAttribute. I would LIKE to add code in the MySpecialPost attribute to inject that functionality.
So my question:
How would I add code to perform this kind of check in this Attribute?
For now, we have not found the solution we wanted and are simply pasting that code (well, a function call with that code in it) at the beginning of EVERY controller.

ASP.NET MVC Login ReturnUrl always NULL?

Using Forms Authentication in ASP.NET MVC when trying to log back into a site, it puts a ReturnUrl parameter in the query string. My Logon action method accepts a "returnUrl" string. However it seems that returnUrl string is always null, even when it is clearly in the query string. Any thoughts on why this might be the case or a possible fix?
This tends to happen when you're using one generic logon form, but you're explicitly specifying the Controller and ActionMethod (which is causing a form post, but losing the querystring)
Just to clarify, this is what your code should look like in your BeginForm:
Html.BeginForm("LogOn", "Account", new { ReturnUrl = Request.QueryString["ReturnUrl"] })
EDIT: This is by design as RickAnd mentions in comments below. However it doesn't allow for the UI pattern of being deep in a site, clicking on LogOn, then returning to the page you were previously on, if it allows anonymous users. It's a commonly requested pattern. David Allen's approach to LogOff would also work nicely for a clean redirect at LogOn.
Maybe you don't include the ReturnURL parameter into you login form's action attribute, thus posting to a URL without that parameter?
Basically, The Asp.net MVC has some hidden features. For Example when you pass variable 'id' to controller action, it interprets 'id' as default identifier and puts it on browser query with fore slash.By using another name instead of 'id' we will see '?' rather than fore slash. Because of setting the 'id' name on RegisterRoutes method on global.asax file.
In this Problem you have created a custom data passer to controller by using this code:
using(Html.BeginForm("LogOn", "Account", FormMethod.Post))
{
//form fields
}
So Asp.net MVC ignores other useful data to pass to controller action, and we'll see returnUrl always null.
While, by using this, Asp.net MVC acts Correctly and returnUrl is mounted:
using(Html.BeginForm())
{
//form fields in LogOn View
}
By the way, When we use custom data passer to controller action, must pass another data manually like this:
using(Html.BeginForm("LogOn", "Account", new {ReturnUrl = Request.QueryString["ReturnUrl"] }))
{
//form fields
}
There are two ways I can think of to deal with logon and logoff scenarios.
Dave Beer outlined one way, above.
There is another approach that works in many situations. I used it when I coded the NerdDinner tutorial. The tutorial provides us with a logoff function that logs you off and takes you home. I did not want that. I wanted to return to the page I was on before I logged off. So I modified my Account controller logoff action to look like this
public ActionResult LogOff()
{
FormsService.SignOut();
return Redirect(Request.UrlReferrer.ToString());
}
You can get fancier and pass in a returnUrl and test for it, in case you want to override this behavior. But I don't need that. This achieves the desired result. The Logon can work similarly. Maybe there are ways to use the MVC framework to do this for me, but until I learn them, this is VERY simple and works reliably.
Try the following:
public static MvcForm BeginForm(this HtmlHelper htmlHelper, string id)
{
string formAction = htmlHelper.ViewContext.HttpContext.Request.RawUrl;
TagBuilder tagBuilder = new TagBuilder("form");
tagBuilder.MergeAttribute("id", id);
tagBuilder.MergeAttribute("action", formAction);
tagBuilder.MergeAttribute("method", HtmlHelper.GetFormMethodString(FormMethod.Post), true);
HttpResponseBase httpResponse = htmlHelper.ViewContext.HttpContext.Response;
httpResponse.Write(tagBuilder.ToString(TagRenderMode.StartTag));
return new MvcForm(htmlHelper.ViewContext.HttpContext.Response);
}
First ensure you have set the login url in the web.config, Next, ensure your Signin Form does not contain anything like action, for example:
View:
If you specify action you will always get null for return url:
Controller:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult SignIn(string userName, string password, bool? rememberMe, string returnUrl)
{
}

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