I wanted to put a random image on every viewpage of my mvc project. So i created a method that returns a partialView and call that method in the shared Layout page.
This works fine when I try to login with a correct username and password. The used is loged in and every page contains a random image. But when I give the invalid combination of username and password. The shared layout page does not find the controller I want to call with my #Html.Action and actualy the login view should be returned with an error message 'invalid combination of username and password' and ofcourse, with the random image.
InnerException:
{"A public action method 'RandomSponsor' was not found on controller 'Project.WebUI.Controllers.HomeController'."}
My Html.Action in shared layout.
#Html.Action("RandomSponsor", "Home")
Method in homecontroller.
[HttpGet]
[ChildActionOnly]
public ActionResult RandomSponsor()
{
var model = service.getRandomSponsor();
return PartialView("RandomSponsor", model);
}
The getRandomSponsor method works fine, this one always returns one random string value that is returned to the RandomSponsor.cshtml view.
RandomSponsor.schtml (only contains the image string)
<img src="~/Content/Images/Advert/#(Model)" alt="a" />
I searched the web for this problem but didn't found a solution, does anyone know the answer to this one?
Might it be something with HttpGet of HttpPost?
Regards.
If the executing request is a POST, then it will try to find a method RandomSponsor accepting HttpPost. If this makes sense, you could remove HttpGet and that should do the trick.
This can also happen if you have many layers of calls that start with a POST (I had an action returning a view returning a partial view calling RenderAction), then the call to RenderAction will still look for a POST method
Very similar to this problem that I had here - How to solve "public action method 'methodActionName' was not found on controller 'controllerNameController'"
And if you want to continue to accept the HTTP GET verb and fix the problem of cascading post request into a get request add this to your method
[AcceptVerbs(HttpVerbs.Get | HttpVerbs.Post)]
Keep in mind that [HttpGet] is the same as [AcceptVerbs(HttpVerbs.Get)]
This will happen if the request is a POST but the controller method is annotated [HttpGet]. For example, you might issue a POST that returns a view containing partial views called with #Html.Action, using controller methods annotated with [HttpGet]. If the original request is a POST, all of the controller methods subsequently called will need to support POST.
To fix it you can use the AcceptVerbs attribute to specify that your controller method accepts both POST and GET:
[AcceptVerbs(HttpVerbs.Post | HttpVerbs.Get)]
Received this error all of the sudden on several different PartialViews (not all of them) when customizing an install of MVCForum. We had not made any changes to the methods or views concerning the errors so it was really frustrating as to why they were broken.
After trying the other solutions on this post and others, went back through the changes made and what ended up stopping the errors was that we had changed the bindings in IIS to another domain that had the 'enforce lower case url' URL Rewrite rule enabled.
When we disabled the enforce lowercase rule, the errors stopped and the site worked as it was supposed to. It's not a URL Rewrite issue (I don't think) because we are able to enforce www using it with no errors. It's a lowercase rewrite issue. Didn't matter if we had the lowercase rule before or after the www rule.
This solution probably doesn't apply to many cases of this error, but it worked for us. Hopefully someone else can benefit from such a simple fix.
I just solved this issue strangely enough on my local PC, by making sure my entire request path was lower case. So give that a try.
I know this is a pretty old thread - but as it's top Google result I thought I'd add a potentially missing link for MVC.Net 5.2.6.
Scenario
I was attempting to call a child action via #Html.Action("ActionName", new { Id = 123})
and received an error much like the above, but none of the other solutions worked. I could hit the controller action externally (i.e. HttpGet), but the child action kept throwing the exception and was driving me nuts!
The solution I found
After two-ing and fro-ing for some time, I started playing with my routing attributes. I had the controller set up as:
[Route("{action}")]
[RoutePrefix("Prefix")]
[RouteArea("AreaName")]
As there was only one public action i wanted, "Index", I removed the {action} and placed an explicit route attribute on the public action and put my ChildActionOnly attribute back on the child.
After I did that, I hit the run and hey presto - the action was hit.
Might be worth a try if you're getting this error while using attribute routing. Note I did attempt to route the child action and this didn't work.
In my case, the same issue was happening randomly with the implicit :
using (Html.BeginForm())
Changing above to :
using (Html.BeginForm("Action","Controller", FormMethod.Post))
fixed this issue.
Did you give it a shot with Html.RenderAction? It is typically faster then Html.Action as it interact directly into the response stream as opposed to building a string.
You can view the following topics for more info:
What is the difference (if any) between Html.Partial(view, model) and Html.RenderPartial(view,model) in MVC2?
Html.Partial vs Html.RenderPartial & Html.Action vs Html.RenderAction
Another thing to note is that for Html.Action or Html.RenderAction, your view doesn't need to be in Shared folder, that is only required if you use Html.Partial or Html.RenderPartial
Related
I have some partial actions that I render with the Asp.Net Futures RenderAction method. Some of these perform redirects after the forms in them have been processed.
Now that I upgraded to Asp.Net MVC 2 RC it gives me an error "Child actions are not allowed to perform redirect actions".
I checked out the source code and I found the line that throws the exception. To Get around it I can make a custom RedirectResult, But before I do I want to understand why the framework doesn't allow it in the first place. There must be a good reason and maybe I Shouldn't do either.
Any one know the reason for this limitation?
Thanks
The limitation exists because MVC has already started rendering a view to the client. The effect of redirecting from this point is undefined. It could work perfectly, it could continue rendering the original view without redirecting, it could throw a different exception, etc.
Since the result of performing this action is undefined, the framework blocks it. In practice, RenderAction should never be used to render anything other than a view (or view-like content) for similar reasons.
In your particular case, the outer action should redirect. If you're just going to end up redirecting from within the view anyway without showing anything to the user, then there was really no purpose to going through the view in the first place, as the outer action could have delegated the work appropriately on its own.
Try to use something like this in Child Action:
ControllerContext.HttpContext.Response.Redirect(ControllerContext.HttpContext.Request.Url.ToString());
My solution.
Action method:
return View("Redirect", model);
View:
<script type="text/javascript" language="javascript">
document.location = '<%: Url.Action("Index", "Album", new { id = Model.Id }) %>';</script>
In my case, the form being rendered is a "configure" panel on an extension to a website I'm building. I'd like the extension's own controller to be able to handle the form processing and then redirect back to the admin page listing all configured extensions. I don't think it's appropriate or practical here to ask the parent page's controller to process the form for the extension. What would you suggest I do instead?
In my unusual case, I had a custom AuthorizeAttribute attached to my controllers which was attempting to redirect on a child action, which is (as mentioned above) not allowed.
To resolve the issue, I removed authorisation checking redirection on all child actions:
Public Overrides Sub OnAuthorization(filterContext As AuthorizationContext)
//Child actions cannot redirect anyway, so no need to check permissions.
If filterContext.IsChildAction Then Exit Sub
.. parent authorisation checks ..
Sometimes this error occured when you try to render an action of base action result.
Example:
ActionResult X
Return View
View X
RenderAction Y
ActionResult Y
// Bla bla
return View
// else
return RedirectToAction X
In that case just point the partial view form's submit url to action that was the target of your problematic redirection and let it perform itself redirection to its GET version.
I am very new to MVC and trying to migrate asp.net application to MVC. Basically I am trying to reuse the code where ever possible. In one case I was trying to use Redirect("SomeUrl") and it works pretty well with the view under same controller.
For eg., I added below piece of code in HomeController.cs
public ActionResult Login()
{
return Redirect("HomeMgr?Section=home&Type=Mgr");
}
Well, could someone suggest me if I can use Redirect(Url) to redirect to a view in another Controller? is there any format for Url something like
"~/controllername/Viewname?something=something&something=otherthing"
(I've read in other posts that I can achieve this using RedirectToAction, but I am trying not to change existing code which uses querystring values. )
Don't use Redirect to redirect to Actions in your app. There are several reasons for this. First, it's just simpler to user RedirectToAction as Alundra's answer provides. However, simpler is only part of the answer.
There's a problem with using Redirect. And that has to do with the way Routing works in MVC. In MVC, you can reach the same action via multiple different URL's. For instance, in a default MVC template, the following are all valid URL's.
http://yoursite/
http://yoursite/Home
http://yoursite/Home/Index
Now, what happens when you use Redirect? If you use the last url, it will work fine. You'll end up with the following url.
http://yoursite/Home/HomeMgr?Section=home&Type=Mgr
But if you're at any of the others, you have a problem...
http://yoursite/HomeMgr?Section=home&Type=Mgr
Oops... that won't work... That will be looking for a controller named HomeMgrController.
You get the same at the root as well.
Using RedirectToAction solves this problem, as it takes your routing into account and will figure out the correct url to redirect you to based on the Controller and Action you specify.
return RedirectToAction("ActionName", "ControllerName", new { Section=home,Type=Mgr ......Anythingelse you want to pass });
I have just spent 2 hours trying to work out why when I put a string in to View.Bag/ViewData inside my Surface controller, when I try and get the string back in the view I get null.
In the end I have solved the problem by putting the string in to a session variable insted.
Would like to know though why it wasn't working, and how to fix it.
Thanks in advance.
Update: Are you posting and redirecting? When you refresh the form does it prompt you about posting again? If not, it's because you have accidentally followed the best practice of 302ing from a form post (prevents a user refreshing and reposting form data). The examples I was following for login surface controllers all used return RedirectToCurrentUmbracoPage() which I blindly followed. But, as the name implies that really is doing a redirect and it is really two requests! (I stubbornly had to verify in Fiddler before I believed it). ViewData and ViewBag are only good for one request--so they are fundamentally broken in a POST 302. Session is good for multiple requests which is why it worked for you. TempData will work for you too, because as it turns out, TempData is a construct that is built on top of session and was specifically designed to carry state between two posts (removed on retrieve). I read somewhere that TempData would have been better named RedirectData and that helped it click for me.
So when you're dealing with Surface Controllers and POSTing you have three options that I know work:
Session (which you proved worked)
TempData (which is built on session, and from what I've read is both best practice and built specifically for this situation)
Use return CurrentUmbracoPage(); in your form post. I just verified in Fiddler that this is exactly one request (refreshing in the browser prompts a repost warning). I also verified that ViewData works this way. But, because the surface controller is rendered as a Child Action using #Html.Action(...) you have to use ParentActionViewContext to get at the right ViewData (my first answer which I'll leave for others that find this question).
Original answer is still useful when there is no redirect involved (GET or a POST that returns CurrentUmbracoPage())...
In many cases you're actually making a child action. Usually you're only one level deep but if you mix macros and partials you can actually get multiple levels deep. There is a ViewData for each level and you have to walk your way up the stack with ParentActionViewContext to get to the top ViewData that you populated in your controller.
See this comment from Shannon in answer to a question about surface controllers and viewdata (Shannon is a core contributor on the HQ team and has a lot of great content out there). Quoting here:
If you want to access the ViewData that you've set on the master ViewContext's on a ChildAction being rendered from the master's ViewContext then you need to use #ViewContext.ParentActionViewContext.ViewData["ErrorMessage"]
The ParentActionViewContext in this example is the ViewContext that is rendering the Umbraco template, not the ChildAction. That is because when you POST (whether inside of Umbraco or normal MVC), you are posting to a new Action and the rendering process starts from scratch, when you validate your model, update the ViewData, etc... this all happens on what will become the 'master' ViewContext when the view renders. This view then will render your ChildAction.
Twamley's answer above is excellent, in addition to this, I have found that using TempData.Add(key, value) works nicely.
An bare bones would look like:
SurfaceController
public class MyController : Umbraco.Web.Mvc.SurfaceController
{
public MyController()
{}
public ActionResult DoSomething()
{
// surface controller does something
// get a page by it's document/model type alias
var umbracoHelper = new UmbracoHelper(UmbracoContext.Current);
var node = umbracoHelper.TypedContentSingleAtXPath("//" + "Home")
TempData.Add("Message", "This value will be passed through");
return redirectToUmbracoPage(node);
}
}
View
#inherits UmbracoTemplatePage
#{
Layout = null;
}
#if (TempData.ContainsKey("Message"))
{
<p>#TempData["Message"]</p>
}
http://localhost/umbraco/Surface/My/DoSomething
When I use RedirectToAction("MyView", "MyController") sometimes the redirection is very slow to render the destination view.
It doesn't always happen.
I am using ASP.net MVC4 with IIS7.5
How can I prevent this problem and speed up the redirection?
I will put this here as code will not show very well in the comments section. If the action method you are redirecting to is in the same controller you are currently in, it is simpler and more efficient to call that method directly and return its results instead of the redirect response generated by the RedirectToAction method. Just to make sure we are on the same page, RedirectToAction actually returns a redirect response (302) to the client asking it to issue a new request to the action method you have specified as per MSDN http://msdn.microsoft.com/en-us/library/system.web.mvc.controller.redirecttoaction(v=vs.108).aspx. Some code to illustrate:
public ActionResult MyAction(){
//do some work here
Return View(MyModel);
}
public ActionResult ActionIAmCurrentlyIn(){
//Do Soe work here
return RedirectToAction ("MyAction", "MyController"); //This costs an extra trip across the wire
return MyAction(); // Does same thing but without the extra trip to the client
}
This overhead of the extra trip becomes more significant if there are parameters being passed along to "MyAction" and as the network speed goes down.
Responding as an answer because I don't have enough rep to add a comment...
#JTMon In your code the "return MyAction();" can cause potential issues because the "MyAction" action will actually try to load a view named "ActionIAmCurrentlyIn" since that is the action that's specified in the route values (at least I assume that's where it's getting it from, I haven't actually dug into the code to find out).
This can be resolved by specifying the view name in MyAction:
return view("MyAction", MyModel);
To prevent this problem and speed up the redirection use:
return Redirect("~/MyController/MyView");
This approach will not change client-server interaction.
You can use RedirectToActionPermanent("View","Controller"); for it.
I have some partial actions that I render with the Asp.Net Futures RenderAction method. Some of these perform redirects after the forms in them have been processed.
Now that I upgraded to Asp.Net MVC 2 RC it gives me an error "Child actions are not allowed to perform redirect actions".
I checked out the source code and I found the line that throws the exception. To Get around it I can make a custom RedirectResult, But before I do I want to understand why the framework doesn't allow it in the first place. There must be a good reason and maybe I Shouldn't do either.
Any one know the reason for this limitation?
Thanks
The limitation exists because MVC has already started rendering a view to the client. The effect of redirecting from this point is undefined. It could work perfectly, it could continue rendering the original view without redirecting, it could throw a different exception, etc.
Since the result of performing this action is undefined, the framework blocks it. In practice, RenderAction should never be used to render anything other than a view (or view-like content) for similar reasons.
In your particular case, the outer action should redirect. If you're just going to end up redirecting from within the view anyway without showing anything to the user, then there was really no purpose to going through the view in the first place, as the outer action could have delegated the work appropriately on its own.
Try to use something like this in Child Action:
ControllerContext.HttpContext.Response.Redirect(ControllerContext.HttpContext.Request.Url.ToString());
My solution.
Action method:
return View("Redirect", model);
View:
<script type="text/javascript" language="javascript">
document.location = '<%: Url.Action("Index", "Album", new { id = Model.Id }) %>';</script>
In my case, the form being rendered is a "configure" panel on an extension to a website I'm building. I'd like the extension's own controller to be able to handle the form processing and then redirect back to the admin page listing all configured extensions. I don't think it's appropriate or practical here to ask the parent page's controller to process the form for the extension. What would you suggest I do instead?
In my unusual case, I had a custom AuthorizeAttribute attached to my controllers which was attempting to redirect on a child action, which is (as mentioned above) not allowed.
To resolve the issue, I removed authorisation checking redirection on all child actions:
Public Overrides Sub OnAuthorization(filterContext As AuthorizationContext)
//Child actions cannot redirect anyway, so no need to check permissions.
If filterContext.IsChildAction Then Exit Sub
.. parent authorisation checks ..
Sometimes this error occured when you try to render an action of base action result.
Example:
ActionResult X
Return View
View X
RenderAction Y
ActionResult Y
// Bla bla
return View
// else
return RedirectToAction X
In that case just point the partial view form's submit url to action that was the target of your problematic redirection and let it perform itself redirection to its GET version.