Return action doesn't change URL - c#

I was looking for a way to redirect with POST and the solutions I've found suggest simply using the action's name I want and fill the params. All of this within the same controller (let's call it Home)
[HttpPost]
public ActionResult Zoro(NameOfMyModel model, string stringName)
{
//Do whatever needs to be done
return Foo("bar",123);
}
[HttpPost]
public ActionResult Foo(string Name, int Age)
{
//Code here that use the params
return View();
}
So that works great except that when you look at the url, it doesn't show /Home/Foo, it shows /Home/Zoro. Can I fix this without using RedirectToAction? If I use it, I get this: Home/Foo?Name=bar&Age=123 Which I don't want.

Instead of calling directly calling Foo() use RedirectToAction() with this overload of it.
The way you doing calls the action on server but not actually redirects, if you want the url to change you have to redirect to the action:
return RedirectToAction("Foo", new {Name = "bar", Age = 123});
UPDATE:
As in comments mention how to keep the data temporarily ,you can use TempData[] for it:
TempData["Name"] = bar";
TempData["Age"] = 123;
return RedirectToAction("SomeAction");
and in that action you can get it from TempData:
public ActionResult SomeAction()
{
string Name = TempData["Name"] as string;
int Age - TempData["Age"] as int;
return View();
}
NOTE:
Note that RedirectToAction() only works with actions which are HttpGet, it will not work with HttpPost actions.

Related

RedirectToAction and pass a value?

If I have a controller action to redirect to another action like so:
public ActionResult Index()
{
RedirectToAction("Redirected", "Auth", new { data = "test" });
}
public ActionResult Redirected(string data = "")
{
return View();
}
The URL bar will have something like "Redirected?data=test" in it, which AFAIK is the proper behavior. Is there a way I can pass a variable directly to the Redirected ActionResult without a change on the client?
I'd like to pass "test" directly to the Redirected ActionResult without the URL changing. I'm sure there's a simple way to do this, but it is escaping me.
I know I can make a static variable outside the functions that I can pass the variable to and from, but that doesn't seem like a proper solution.
You can use TempData variable.
public ActionResult Index()
{
TempData["AfterRedirectVar"] = "Something";
RedirectToAction("Redirected", "Auth", new { data = "test" });
}
public ActionResult Redirected(string data = "")
{
string tempVar = TempData["AfterRedirectVar"] as string;
return View();
}
This link could be helpful.
Yes, use TempData.
public ActionResult Index()
{
TempData["data"] = "test";
RedirectToAction("Redirected", "Auth"});
}
public ActionResult Redirected()
{
var data = TempData["data"].ToString();
return View();
}
I hope this could help you:
https://stackoverflow.com/a/11209320/7424707
In my opinion TempData isn't the most proper solution. If I were you I would look for another solution.
Otherwise, do you really need to call RedirectToAction (to call an action from another controller)? Or are your actions in the same controller for instance?

Does going from one Action method to the other action method clear class variables?

So in the same controller I have a Login Action method like this:
public ActionResult Login()
{
LoginModel model = this.LoginManager.LoadLoginPageData();
this.ForgotPasswordMethod = model.ForgotPasswordMethod;
return View(model);
}
Notice I set a variable there: ForgotPasswordMethod
So now when there on that page if they click on a link, it call another action result in the same controller class like this:
public ActionResult ForgotPassword()
{
if (!string.IsNullOrWhiteSpace(this.ForgotPasswordMethod) && this.ForgotPasswordMethod.Trim().ToUpper() == "TASKS")
return View();
return null; //todo change later.
}
Notice I tried to read the value of ForgotPasswordMethod , but it was NULL but it is NOT null when I am in the Login() method. So what should I do?
ASP.NET MVC was designed to return back to a cleaner, more straightforward web world built on HTTP, which is stateless, meaning that there is no "memory" of what has previously occurred unless you specifically use a technique that ensures otherwise.
As a result, whatever state you set via one ActionResult will no longer be the same state that exists when another ActionResult is invoked.
How do you "fix" this? You have a variety of options, depending on what your needs are:
Render the value to the client and post the value back to your second ActionResult method.
Store the value as a header and check that header.
Store the value in a cookie and check the cookie.
Store the value in session.
Store the value in a database.
Store the value in a static dictionary.
what if you store forgotpasswordmethod in Viewbag like
public ActionResult Login()
{
LoginModel model = this.LoginManager.LoadLoginPageData();
Viewbag.ForgotPasswordMethod = model.ForgotPasswordMethod;
return View(model);
}
then in the link of your page you can pass the value from the ViewBag
<a href=#Url.Action("ForgotPassword", "Name of your Controller", new { methodName = ViewBag.ForgotPasswordMethod })>Forgot Password</a>
Change your forgotpassword to
public ActionResult ForgotPassword(string methodName)
{
if (!string.IsNullOrWhiteSpace(methodName) && methodName.Trim().ToUpper() == "TASKS")
return View();
return null; //todo change later.
}

ASP.NET MVC Return Overloaded Get Action

I am using MVC 4, and I have the following:
[HttpGet]
public ActionResult SomeForm(modelType model = null)
{
if(model != null)
return View(model);
return View(getModelFromSomewhere());
}
[HttpPost]
public ActionResult SomeForm(modelType model)
{
if(isValid())
doSomething();
else
return SomeForm(model) // Line in Question
}
However, obviously, I am getting an ambiguous method error on "Line in Question". I'm wondering if anyone has an elegant solution to be able to specify to return specifically the [Get] method of the same name?
Thank you!
You can't have methods with the same signature as you've pointed out already. In C# it also means you can't distinguish functions by just return type - so you must use different names if parameters are same (again default values are ignored when matching of signatures).
If you want separate GET and POST handler - use different names of methods and ActionNameAttribute to name the action:
[HttpGet]
[AciontName("SomeForm")]
public ActionResult SomeFormGet(modelType model = null) ...
[HttpPost]
[AciontName("SomeForm")]
public ActionResult SomeFormPost(modelType model) ...
make it compile...
[HttpPost]
public ActionResult SomeForm(modelType model, FormCollection fc)
{
if(isValid())
doSomething();
else
return SomeForm(model) // Line in Question
}
If you are using http get method you are waiting that browser will send you serialized model as a string query. For example, you are waiting url like
http://example.com?name=Andrew&type=Worker&field1=param1&field2=param2&....
It is common practice to use only id in your get method, so you can do it like this:
[HttpGet]
public ActionResult SomeForm(int id)
{
var model = FindModelById(id);
if(model != null)
return View(model);
return View(getModelFromSomewhere());
}
If you are looking for an elegant solution, it will be more elegant in architecture

MVC passing complex object to action

I have two actions in my controller when a user call one i need to redirect it to another one and pass a complex object :
first action :
public virtual ActionResult Index(string Id) {
var input = new CustomInput();
input.PaymentTypeId = Id;
return RedirectToAction(MVC.Ops.SPS.Actions.Test(input));
}
second action :
public virtual ActionResult Test(CustomInput input) {
return View();
}
The probelm is that the input arrives null at the second action. how can i solve it?
You can solve this using temp data to temporarily hold a value from which the second method retrieves that value.
public virtual ActionResult Index(string Id)
{
var input = new CustomInput();
input.PaymentTypeId = Id;
TempData["TheCustomData"] = input; //temp data, this only sticks around for one "postback"
return RedirectToAction(MVC.Ops.SPS.Actions.Test());
}
public virtual ActionResult Test()
{
CustomInput = TempData["TheCustomData"] as CustomInput;
//now do what you want with Custom Input
return View();
}
You can keep your tempData going so long as it is never null using the .keep() method like this,
if (TempData["TheCustomData"] != null)
TempData.Keep("TheCustomData");
I want to make sure that you know that RedirectToAction creates new HTTP request so this create another GET and all you can pass is RouteValueDictionary object which is like having query string parameters which is list of key and value pairs of string. That said, You can't pass complex object with your way of code however the TempData solution mentioned by #kyleT will work.
My recommendation based on your code is to avoid having two actions and redirect from one another unless you are doing something more than what you have mentioned in your question. Or you can make your Test action accepting the id parameter the your Index action will contain only RedirectToAction passing the id as route parameter.
Edit:
Also, If you have no primitive properties you can pass your object like the following (Thanks to #Stephen Muecke)
return RedirectToAction("Test",(input);

Is it possible to have 2 views associated with one action?

I have the following custom route
routes.MapRoute("custom", "Groups/{groupname}/{action}/{id}", new { controller = "Groups", action = "Index", id = UrlParameter.Optional });
This custom route is to achieve the following url schema
Groups/pokerclub/members/ - list all the members of pokerclub group.
Groups/pokerclub/members/bob - list member details of bob.
I tried the following but it doesnt work. it confuses asp .net mvc of which action to select.
public ActionResult Members(string groupName, string id)
{
return View();
}
public ActionResult Members(string groupName)
{
return View();
}
There are two possible solutions that i could think of:
Have different action name. e.g. Memberlist action and member action.
Handle this in the view using simple if statement.
I very much want to maintain my url scheme. thus, as per my original question, how to have two different views associated to one action? Thanks.
RWendi
You can only have one action, but you can perform whatever logic you want inside that action, and you can call views by name:
return View("MyView");
In your example, you would simply return a different view if the id field was null.
where it says return View(); It takes parameters and you can get it to use whatever view you would like
return View("Members", model);
you can use different methods:
[HttpGet]
public ActionResult Members(string groupName, string id)
{
return View();
}
[HttpPost]
public ActionResult Members(string groupName)
{
return View();
}

Categories