How can I determine if current action is a ChildAction or routed main action? Should I check the URL and compare to the action's name? That's not so nice, since it's dependent on routing patterns...
Or should I make two actions of the same name, put a ChildActionOnly on one of them and have separate logic (mainly returning View() or PartialView())? How will the overloads be differentiated?
Okay, from an other perspective: How to make it so, that if it's a ChildAction then return a PartialView, otherwise a full View?
You could use the IsChildAction property:
public ActionResult Index()
{
if (ControllerContext.IsChildAction)
{
// The Index action was invoked as child action using
// #Html.Action("index")
}
...
}
Related
I am using nopCommmerce 3.40 , MVC 5
I have make plugin and make route one route for action
But i am getting error look like :
Error executing child request for handler'System.Web.Mvc.HttpHandlerUtil+ServerExecuteHttpHandlerAsyncWrapper'.
Child actions are not allowed to perform redirect actions
My Code
[AdminAuthorize]
public ActionResult Configure()
{
return RedirectToRoute("PluginName.ActionName");
}
public ActionResult ActionName()
{
// i want to call/ return this from Configure mathod
}
RouteProvider
routes.MapRoute("PluginName.ActionName", "Admin/Plugins",
new { controller = "Controller", action = "Action" },
new[] { "PluginName.ActionName.Controllers" }
).DataTokens.Add("area", "admin");
The error message you get says it all. You cannot perform a redirection there. Plugin configure actions are, in fact, invoked using child actions and, therefore, are usually decorated with the [ChildActionOnly] attribute. You can find a more detailed message at this answer Why are Redirect Results not allowed in Child Actions in Asp.net MVC 2.
You should refactor your code to call the redirection from some other place like the main action or a custom action filter applied to the main action, for instance.
But, since the code that calls your Configure action is out of your control because it belongs to nopCommerce, not to your plugin, your best shot is to inject a custom action filter dynamically and perform the redirection there.
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 get the actual "Main-Controller" in a RenderAction?
Example:
MyRoute:
{controller}/{action}
My url my be:
pages/someaction
tours/someaction
...
In my Site.Master I make a RenderAction:
<% Html.RenderAction("Index", "BreadCrumb"); %>
My BreadCrumbController Action looks like this:
public ActionResult Index(string controller)
{
}
The strings controller contains "BreadCrumb" (which is comprehensible because actually I am in BreadCrumbController).
What's the best way to get the "real" controller (e.g. pages or tours).
Parent view/controller context
If you use MVC 2 RC (don't know about previous releases) you can get to parent controller via view's context, where you will find a property called:
ViewContext ParentActionViewContext;
which is parent view's context and also has a reference to its controller that initiated view rendering...
Routing
It seems to me (from your question) that you have requests with an arbitrary number of route segments... In this case you have two options:
Define your route with a greedy parameter where actions in this case will catch all actions in your request URL
{controller}/{*actions}
Create a custom Route class that will handle your custom route requirements and populate RouteData as needed.
the second one requires a bit more work and routing knowledge but it will help you gain some more knowledge about Asp.net MVC routing. I've done it in the past and it was a valuable lesson. And also an elegant way of handling my custom route requirements.
Could you pass it as a parameter to the controller?
--Site.master--
<% Html.RenderAction("Index", "BreadCrumb"
new { controller = ViewData["controller"] }); %>
--BreadCrumbController.cs--
public ActionResult Index(string controller)
{
}
--ToursController.cs--
public ActionResult SomeAction(...)
{
// ....
ViewData["controller"] = "Tours"
// You could parse the Controller type name from:
// this.ControllerContext.Controller.GetType().Name
// ....
}
What do you mean with "real" controller? Your action points to one controller.
Do you mean the previous controller? So: the controller that was used to render your view where your link was created that points to your breadcrumbcontroller?
Unless you add the name of that controller to the link as a parameter, there is no way to get to that.
I'd like to get access to the current executing Controller so I can offload the return of the appropriate ActionResult onto a helper method. To this end, I'm looking for the equivalent of what I would have thought would be ControllerContext.Current but isn't. Thanks!
Edit for clarification: I've got a generic form control which is JavaScript-based but I'd like to add an option so that it works with noscript. At the moment my Controller sets the ViewData.Model to a JSON-ified Models.FormResponse<T>.
This FormReponse is set up with the status of the post and any error messages that were generated, so I'd like a GetActionResult() method which does the script/noscript check (a hidden form input) and either:
Sets the Model to the JSONed FormResponse and returns a View(), or
Serializes the FormResponse to the Session and returns a Redirect().
As this obviously changes the return value and I don't want to do the check myself every time, I need to call View or Redirect from the FormResponse's GetActionResult method in order to call this as:
return formResponse.GetActionResult();
I know with a more astronautical design this could be made even more robust but as the noscript option is not a major feature at the moment, I just need to get a quick solution working that doesn't break other things.
Update #2
The following, implemented in an ActionResult class, does the job for me. Thanks CVertex!
public override void ExecuteResult(ControllerContext context)
{
if (CMSEnvironment.NoScript)
{
Oracle.Response.Redirect(Oracle.Request.UrlReferrer.ToString(), true);
}
context.Controller.ViewData.Model = _model.ToJSON();
new ViewResult()
{
ViewName = Areas.Site.Helpers.SharedView.Service,
ViewData = context.Controller.ViewData
}.ExecuteResult(context);
}
Statics are bad for testability, and very much discouraged in MVC.
Why do you want to access the current controller and action method?
The best way to do this is to implement your own ActionFilter.
This gives you a means of intercepting requests before or after actions methods execute.
EDIT:
By intercepting the result inside OnActionExecuted of a filter, you can do your noscript/script checks and modify your ViewData accordingly for consumption by the View.
Inside OnActionExecuted, you can also do the noscript check and have complete control over the final ActionResult or the ViewData, as you please.
Or, you can write your own ActionResult that makes all these decisions.
So, your controller action ultimately does
return new MyActionResult(format_and_view_agnostic_model_object);
There doesn't appear to be a way to navigate to the current Controller from a thread. That is you could get the ControllerBuilder and you can get the MvcHttpHandler but neither then lets you access the controller instance that the handler is using.
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.