I am using ASP.NET MVC C#. I have my view with the following line of code:
#using (Html.BeginForm("TastingParty", "Contact"))
I am submitting to a different controller and action than the current page is on so I had to add a custom controller and action in that line. Now it gets to my controller and at the bottom of the method I call "return View();" so it will display the same page again. But it is looking for that view in the Contact controller because that is where I sent it.
How do I return the original View that it came from? Hopefully that all makes sense.
return RedirectToAction(Action,Controler)
You are searching for this?
You can either use return RedirectToAction(...
http://msdn.microsoft.com/en-us/library/system.web.mvc.controller.redirecttoaction(v=vs.118).aspx
Or, if you want to be able to reuse the view across different controllers, you can place it in the Views\Shared folder.
In the latter case, you then have the ability to return the posted model back out to that view.
public ActionResult YourAction(YourViewModel postedModel) {
// do something
return View(postedModel);
}
And again, if you want this to be a shared view, you could place it under Views\Shared\YourAction.cshtml.
Related
In MVC 5 I am attempting to use the controller to render a partial view only if the (Windows Authenticated) user belongs to one or more of a list of Active Directory groups. There are over 30 distinct groups I need to account for, so the "hello world" examples don't fit my needs. After playing scavenger hunt on the web, I managed to collect this much. No compile or runtime errors, but the content is showing for all users rather than the specific users. So the desired outcome is not yet achieved.
While I can achieve the desired outcome using if-then logic in the view, it creates a lot of unnecessary duplication and encourages spaghettification. So I'm trying to do this in the controller.
Summary of Desired Outcome:
When the user loads the viewpage, the partial view should only render if the Windows Authenticated user belongs to one or more of a list of groups defined in the controller action. If the user is not authorized, then the partial view is not included.
Controller Block:
[ChildActionOnly]
[Authorize(Roles="Domain\\GroupA,Domain\\GroupB")]
public ActionResult MonitorCSU()
{
return PartialView("MonitorCSU");
}
View Block:
<div class="rowWithCols3">
#Html.Partial("MonitorCSU")
Unsuccessful Iterations:
In the controller block I tried (unsuccessfully) to use an if-then block, the else case being another partial view with no content.
[ChildActionOnly]
public ActionResult MonitorCSU()
{
if (User.IsInRole("Domain\GroupA")) {
return PartialView("_MonitorCSU");
}
else
{
return PartialView("_Unauthorized");
}
}
In Razor, I tried using HTML.Action but when I tried run the page the browser hung in an infinite loop.
#Html.Partial() returns a partial view without calling a controller method. In order to call your controller method, you need to use
#Html.Action("MonitorCSU")
or
#{ Html.RenderAction("MonitorCSU") }
Note this assumes that the MonitorCSU() method is in the same controller as the method that generates the main view (other wise you also need to include a parameter for the controller name)
Refer documentation
While you've found a solution, you're going to have other problems with it. I would suggest a different approach, which is to use EditorTemplates and create a separate model for the html you want to render. Then, at runtime you would check whether the user is in the groups you specify, and if they are, you create an instance of the model, and if they are not you leave the model null. In this way, when the view is rendered with EditorFor(), it will ignore and not render the template for users who do not have access.
Thanks to #Stephen Muecke and and a commenter whose entry has mysteriously vanished, I have the missing pieces.
I was able to test this code with several real users and verified the desired behavior happens consistently.
Controller Block:
Main difference: take out authorization and use an if-then block send one of two partial views.
[ChildActionOnly]
public ActionResult MonitorCSU()
{
if (User.IsInRole("DOMAIN\\GroupA"))
{
return PartialView("MonitorCSU");
}
else
{
return PartialView("Unauthorized");
// this is an empty page
}
}
View Block:
The key difference is using HTML.Action
<div class="rowWithCols3">
#Html.Action("MonitorCSU")
I am trying to return to view from a controller that has both querystring and model
return View("BillingReport.aspx/?report=" + fc["report_selector"], bilDet);
but this gives me a runtime error of page not found as it appends .aspx etc at the end of the url.
RedirectToAction() doesnt have an option to do it.
Is there a way to do it or does mvc3 limit us to using either a query string or a model
MVC does not support what you are looking for,
But I dont understand why do you want to Redirect To a URL with ModelValues.
Any redirection is a GET request, so you can construct the model and return View from that action.
View() expects a view name and model associated with it.
Redirect() or RedirectToAction() are used to redirect the url to another controller/action. So you can not pass a model.Even if you will try to pass model it will append model properties as querystring parameters.
Here is a reason why you would want use the model and the querystring: the querystring allows you to give user way to save URL with state information. The model allows you to pass a lot of non-flattened data around. So here is I think how to do this in MVC 5 (maybe does not work for older versions, but probably does):
Use 2 actions rather than 1 for the view. use first one to set querystring via RedirectToAction. Use second action to return model to the view. And you pass the model from the first action to the second action via session state. Here is example code:
public ActionResult Index(string email){
Session["stuff"]=Load(email);
return RedirectToAction("View1action", new { email = email, color = "red" });
}
public ActionResult View1action(string email){
return View("View1",(StuffClass)Session["stuff"]);
}
I agree with Manas's answer and if I were you I would consider changing the design if possible. As a side note, the following technique is possible:
TempData["bilDet"] = bilDet;
return RedirectToAction(....); // your controller, action etc.
On the action you can then retrieve your TempData. TempData will automatically be removed.
But also check out: ASP.NET MVC - TempData - Good or bad practice
I am current working on a MVC C# application and have a HttpPost ActionResult which adds a new role to a user. I want to use this method throughout my application.
The problem I have is once this method has run I want it to return to the previous ActionResult and as I want to reuse this method I can not set the return view to a set view. Is there a way to set the return to the previous View?
Many Thanks
Andrew
You could pass a returnUrl when invoking the POST controller action:
[HttpPost]
public ActionResult Foo(string returnUrl)
{
.... do something
return Redirect(returnUrl);
}
This way you can POST to this controller action from different parts of the application and every time you will provide the return url you want to get redirected to once it has finished processing. This is for example how the LogOn action in the default template works. You may take a look at it.
It will by default return the view which is the same name as the action, not which view the form was submitted from.
If you want to return a specific view then you can do:
return View("ViewName",Model);
If you want to return the view that submitted the form you will need to tell the action where it came from, so you can add a property to your viewmodel that was set in the view. Then you could do:
return View(ViewModel.ViewName,ViewModel);
You might be able to do something nasty by digging the viewname out of the request object, but that is so horrible I am not going to even tell you where to begin.
You can create an ActionFilter which uses a cookie to store the current route values. It loads the previously saved cookie in OnActionExecuting and stores the current route valeus in OnActionExecuted. But it will fail for everyone that has disabled cookies.
You could also use the HTTP header Referrer. But it isn't set all the time.
There are in other words no reliable way to achieve what you want (without using a parameter as described by Darin). At least not a way which is worth the trouble.
In a controller, is it possible to return the view of an action from ANOTHER controller? The other option is to return a partial view, which uses Html.Action(...) to return the view from the other controller, but I was wondering if there's anything cleaner. Thanks.
If it's just the view you want to reuse, you can pass in the path to the view. For example:
public ActionResult MyAction()
{
// do your model magic here
return View( "~/Views/OtherController/View.aspx", model );
}
Or you can move the view to Views/Shared like Kyle already suggested.
Yes, if that view is a Shared view. Place the view in the Views/Shared folder in your MVC Project, then both controllers will be able to return it.
If you want to invoke an action on another controller, you can use Controller.RedirectToAction() and pass in the action and controller name.
However, this adds an additional server round trip. If you want to avoid that, you can use the TransferResult class shown here:
How to simulate Server.Transfer in ASP.NET MVC?
I ended up using my original solution, which was having a shared view that invokes an action. It was much less code than I needed. Thanks.
Here's a strategy I use to invoke another action without having to create a special view just for that purpose:
Create a shared view which takes a model that defines an Action, Controller, and RouteValues, and whose sole responsibility is to call RenderAction with the values on that model.
Next create a helper method on your base controller class that takes an Action, Controller, and RouteValues as parameters, and returns the ViewResult for this shared view. That way, you can reuse this helper method and shared view on all your controllers any time you want to render some other action from another action's context.
Of course, if it's just the view and not the action that you want to invoke, Marnix's answer is correct.
So in order accomplish what I asked in this post I did the following:
[iPhone]
[ActionName("Index")]
public ActionResult IndexIPhone()
{
return new Test.Areas.Mobile.Controllers.HomeController().Index();
}
[ActionName("Index")]
public ActionResult Index()
{
return View();
}
Which still serves the same view as the Index action method in this controller. Even though I can see it executing the Test.Areas.Mobile.Controllers.HomeController().Index() action method just fine. What's going on here? And how do I serve the Index view from Mobile area without changing the request URL (as asked in the original post referenced above)?
You have a few options:
Redirect to the Action you'd like to return: return RedirectToAction("Action-I-Want").
Return the View by name: return View("The-View-I-Want").
Note that with the 2nd approach you'd have to put your view in the "Shared" folder for all controllers to be able to find it and return it. This can get messy if you end up putting all your views there.
As a side note: The reason your work doesn't find the view is because default view engine looks for the view in the folder that "belongs" to the current executing controller context, regardless of what code you're calling.
Edit:
It is possible to group all "mobile" views in the same folder. On your Global.asax (or where ever you're setting up your ViewEngine, just add the path to your mobile View in the AreaViewLocationFormats. Mind you, you'll still have to name your views differently.
You can also write your own view engine. I'd do something like detecting the browser and then serving the right file. You could setup a convention like View.aspx, and View.m.aspx.
Anyhow, just take a look at WebFormViewEngine and you'll figure out what works best for you.
The easiest way to send a request to a view handled by another controller is RedirectToAction("View-Name", "Controller-Name").
There are overloads of View() that take route information that might work as well, but they'd require more effort to set up.
Well actually the easiest way is to make one version of your site programmed on standards instead of browser detection :D -- however in direct response to accomplish what it in a more of a ASP.NET mvc fashion, using:
RedirectToAction("ViewName", "ControllerName");
is a good method however I have found it is more practical if you feel you must program for different browser standards to create a primary view and an alternate "mobile" view under your controllers views. Then instead of writing special code on every controller, instead extend the controller like so.
public class ControllerExtended : Controller
{
private bool IsMobile = false;
private void DetectMobileDevices(){ .... }
}
Then modify your controller classes to instead say ControllerExtended classes and just add the one line to the top of each Action that you have alternate views of like so:
public class ApplicationsController : ControllerExtended
{
// GET: /Applications/Index
public ActionResult Index() {
this.DetectMobileDevices();
if(this.IsMobile){
return RedirectToAction("MobileIndex");
} else {
// actual action code goes here
return View();
}
}
}
Alternately you can use return View("ViewName"); but from my experience you want to actually perform different actions as opposed to just showing the result in a different view as in the case of presenting an HTML table as opposed to a Flex table to help iPhone users since there is no flash support in the iPhone, etc. (as of this writing)