I am trying to create a RenderAction method on the Master page that will dynamically generate a side bar based on the current controller and action. When the RenderAction is called in the view it is populated with the controller and action of that particular RenderAction Method. For Example, if I am on the controller of “Home” and action of “Index” I am expecting "Home" and "Index" in the GenerateSideBar method. Instead I get the controller of “Home” and action of “RenderSideBar”. Thanks For your Help!
My Master Page View:
<div class="side-bucket">
<%
string Controller = ViewContext.RouteData.Values["Controller"].ToString();
string Action = ViewContext.RouteData.Values["Action"].ToString();
%>
<% Html.RenderAction("RenderSideBar", "Home", new { controller = Controller, action = Action }); %>
Controller Action:
public ActionResult GenerateSideBar(string controller, string action)
{
switch (controller.Trim().ToLower())
{
case "member" :
return View(#"sidebar\MemberSidebar");
default:
break;
}
return null;
}
The problem is that controller and action parameter names are special because used in your routes and will take precedence when the default model binder tries to set their values. Simply rename them like this:
public ActionResult GenerateSideBar(string currentController, string currentAction)
{
...
}
and render it:
<% Html.RenderAction("RenderSideBar", "Home",
new { currentController = ViewContext.RouteData.Values["controller"],
currentAction = ViewContext.RouteData.Values["action"] }
); %>
Now you should get the correct parent action name. Also if this action is intended to be used only as child action you could decorate it with the [ChildActionOnly] attribute.
Related
I am trying to pass value from view to action method using ActionLink
#Html.ActionLink("Click here", "GetvaluefromView", "ActionLink2", new { id = 3 })
My controller action method looks like below
[HttpPost]
public ActionResult GetvaluefromView(int ? Str )
{
return View("Methodname");
//http://localhost:1542/ActionLink2/Methodname
}
But this is not passing the value to action method.
Am I missing anything here?
I have partial view like this defined in Products controller:
public PartialViewResult _Comments(int productId)
{
var comments = _CommentsRepo.GetCommentsByProductId(productId);
return PartialView(comments);
}
Partial view is in Shared folder:
In Products view I wrote something like:
#{Html.RenderPartial("_Comments", new { productId = Model.Id });}
but it seems I can't find best overload for me.
It seems I can also use #Html.Action helper.
RenderPartial renders a partial view directly - it doesn't call an action. You need to use RenderAction:
#{ Html.RenderAction("_Comments", new { productId = Model.Id }); }
Or just Action:
#Html.Action("_Comments", new { productId = Model.Id });
For rendering my menu in MVC 3 Razor I have in the Home controller a Menu action: public ActionResult Menu() {...}
This action gets the menu items and render them using a view. In the _Layout I use: #Html.Action("Menu", "Home") for rendering the menu. This works fine.
My problem is that I want to select the current item. For this each action that render an item that is in the menu will add to the ViewBag the selected menu item. The problem is that the ViewBag is empty in the Menu action.
Is this the correct approach? I want to render a menu using a controller + view not only a view. I want this in order to avoid having logic code in the view code and to be able to test it.
Do you know a better approach?
How can I pass data from _Layout.cshtml to an action that I render using #html.Action?
You could pass it as parameter:
#Html.Action("Menu", "Home", new { sleectedItem = (string)ViewBag.SomeItem })
and then in the child controller action use this:
public ActionResult Menu(string selectedItem)
{
...
}
or if all you need is to fetch the current controller and action you could simply fetch this information from the RouteData and get rid of any ViewBag:
public ActionResult Menu()
{
var rd = ControllerContext.ParentActionViewContext.RouteData;
var action = rd.GetRequiredString("action");
var controller = rd.GetRequiredString("controller");
// Now that you know the action and the controller build up your view model
// and pass to the view. It will then know which menu item to preselect
...
}
Try looking at the RouteData from inside an action method or the ViewContext if inside an HtmlHelper extension when constructing your menu. Pull out which is the current controller and which is the current action and set that menu item accordingly.
From an action method:
object controller = RouteData.Values["controller"];
object action = RouteData.Values["action"];
object area = RouteData.DataTokens["area"];
From an html helper:
object controller = helper.ViewContext.RouteData.Values["controller"];
object action = helper.ViewContext.RouteData.Values["action"];
object area = helper.ViewContext.RouteData.DataTokens["area"];
Here is a helper I wrote a while back to print a css class to an active menu: http://blog.tomasjansson.com/2010/09/asp-net-mvc-helper-for-active-tab-in-tab-menu/
I am experimenting with MvcContrib subcontrollers. Looking at the example in the source, your parent controller (HomeController) takes an action which takes the subcontroller (FirstLevelSubController) as a parameter:
public class HomeController : Controller
{
public ActionResult Index(FirstLevelSubController firstLevel)
{
ViewData["Title"] = "Home Page";
return View();
}
}
In Home's index view, you call ViewData.Get like this to render the subcontroller and it's view:
<div style="border:dotted 1px blue">
<%=ViewData["text"] %>
<% ViewData.Get<Action>("firstLevel").Invoke(); %>
</div>
The subcontroller's action gets called (ignore the secondlevelcontroller, the example is just demonstrating how you can nest multiple subcontrollers):
public class FirstLevelSubController : SubController
{
public ViewResult FirstLevel(SecondLevelSubController secondLevel)
{
ViewData["text"] = "I am a first level controller";
return View();
}
}
This all works, the subcontroller's view gets rendered inside the parent view.
But what if I need other parameters in my home controller's action? For example, I may want to pass a Guid to my controller's index method:
public class HomeController : Controller
{
public ActionResult Index(Guid someId, FirstLevelSubController firstLevel)
{
//Do something with someId
ViewData["Title"] = "Home Page";
return View();
}
}
There doesn't seem to be any way to do <% ViewData.Get("firstLevel").Invoke(); %> with parameters. So I can't figure out how to link to my controller from another controller passing a parameter like this:
Html.ActionLink<HomeController>(x => x.Index(someThing.Id), "Edit")
Perhaps I am approaching this the wrong way? How else can I get my parent controller to use a subcontroller, but also do interesting stuff like accept parameters / arguments?
Have a look at this blog post:
Passing objects to SubControllers
http://mhinze.com/passing-objects-to-subcontrollers/
Note that SubControllers are deprecated. They have been replaced with RenderAction.
i have:
AlbumsController
PhotoRepository
Index.aspx (view)
inside of Index.aspx, i have a partial view call AlbumControl. I want to update this via ajax and ajaxhelper.
the issue is that i want the ability to do the following:
http://www.mysite.com/Albums
http://www.mysite.com/Albums?FilterTag=Birthdays
when i do this, i get the following error:
The current request for action 'Index' on controller type 'AlbumsController' is ambiguous between the following action methods:
System.Web.Mvc.ActionResult Index(System.String) on type Controllers.AlbumsController
System.Web.Mvc.ActionResult Index() on type Controllers.AlbumsController
i would have thought that asp.net mvc would have figured it out where if i pass in a parameter in the querystring it would go to the Index(string Tag) method and if i didn't pass in a parameter, it would go to Index().
suggestions?
The problem is that the MVC Routing Engine can't tell the difference between:-
1) Calling Index()
and
2) Calling Index(string tag) with tag = null
That's why it says the request is ambiguous.
You can just do:-
public ActionResult Index(string tag)
{
if(String.IsNullOrEmpty(tag))
{
// index code goes here
return View("Index");
}
else
{
// code to handle filtered view goes here
return View("Tag");
}
}
or you can force the parameter to be required with a custom attribute:-
ASP.NET MVC ambiguous action methods
or you can set up routes so that Albums and Albums?FilterTag=X explicitly go to different actions (Incidentally, I'd recommend "Albums" and "Albums/X"):-
routes.MapRoute("AlbumsIndex", "Albums",
new { controller = "Albums", action = "Index" });
routes.MapRoute("AlbumsTag", "Albums/{tag}",
new { controller = "Albums", action = "Tag", tag = "" });
routes.MapRoute("Default", "{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = "" );
and
public ActionResult Index() { ... }
public ActionRestlt Tag(string tag) { ... }