Scan for all actions in the site - asp.net-mvc

How do I create action links for all actions in the site?
I want to put those action links into a menu system.
I was hoping I can do something like
foreach controller in controllers {
foreach action in controller{
stringbuilder.writeline(
"<li>"+actionlink(menu, action, controller)+"<li>"
);
}
}

Here's my take on it:
var controllers = Assembly.GetCallingAssembly().GetTypes().Where(type => type.IsSubclassOf(typeof(Controller))).ToList();
var controlList = controllers.Select(controller =>
new
{
Actions = GetActions(controller),
Name = controller.Name,
}).ToList();
The method GetActions as follows:
public static List<String> GetActions(Type controller)
{
// List of links
var items = new List<String>();
// Get a descriptor of this controller
var controllerDesc = new ReflectedControllerDescriptor(controller);
// Look at each action in the controller
foreach (var action in controllerDesc.GetCanonicalActions())
{
// Get any attributes (filters) on the action
var attributes = action.GetCustomAttributes(false);
// Look at each attribute
var validAction =
attributes.All(filter => !(filter is HttpPostAttribute) && !(filter is ChildActionOnlyAttribute));
// Add the action to the list if it's "valid"
if (validAction)
items.Add(action.ActionName);
}
return items;
}
If you need a menu system checkout the MVC Sitemap Provider, it will give you absolute control on what to render depending on the roles you've defined on your membership implementation.

Here is approach how get all actions from controller Asp.net Mvc: List all the actions on a controller with specific attribute or Accessing the list of Controllers/Actions in an ASP.NET MVC application
For achieving your goal you should find all controllers in your project with Assembly.GetExportedTypes() and filter only sub classes of ControllerBase and for each controller call new ReflectedControllerDescriptor(typeof(TController)).GetCanonicalActions() from 2nd link.

Related

MVC EditorFor templates not used when calling controller from another controller

Within an MVC project we have an area with a controller SomeController returning a partial view containing EditorFor statements, each with their own template.
Everything works fine if the controller is invoked directly via a route for that area. However, if it's called via another controller outside of the area, i.e. via 'new SomeController().SomeAction()', the templates are not used, even if explicitly specified (the view is returned ok, but shows just default textboxes etc).
What could be the reason for this and how can it be fixed?
When your action is invoked merely using ctrl.Action(), the current RouteData will be used (with the current area/controller/action values in it) and when Razor tries to resolve your EditorTemplates paths it consults the ViewContext that is still containing the (now wrong) values of the originating action.
You better use the ControllerFactory in order to mimic the desired behavior:
var ctrlFactory = ControllerBuilder.Current.GetControllerFactory();
var routeData = new RouteData();
routeData.DataTokens.Add("area", "target_area_name");
routeData.Values.Add("controller", "target_controller_name");
routeData.Values.Add("action", "target_action_name");
var requestContext = new RequestContext(this.HttpContext, routeData);
var ctrl = ctrlFactory.CreateController(requestContext, "target_controller_name") as TargetControllerType;
if (ctrl != null)
{
ctrl.ControllerContext = new ControllerContext(requestContext, ctrl);
var ctrlDesc = new ReflectedControllerDescriptor(typeof(TargetControllerType));
var actionDesc = ctrlDesc.FindAction(ctrl.ControllerContext, "target_action_name");
var result = actionDesc.Execute(ctrl.ControllerContext, new Dictionary<string, object>()) as ActionResult;
this.RouteData.DataTokens["area"] = "target_area_name";
this.RouteData.Values["controller"] = "target_controller_name";
this.RouteData.Values["action"] = "target_action_name";
return result;
}
See MSDN

How to capture the values in a gridview dynamically in asp.net DevExpress MVC

as I can make this code dynamically
public ActionResult EditingUpdate()
{
//...
string fName = GridViewExtension.GetEditValue<string>("FirstName");
string lName = GridViewExtension.GetEditValue<string>("LastName");
//...
}
There are several ways of doing this, it depends on how you want to present the action to the user. I would recommend you follow the example on the DevExpress Demo Page. They show you how to pass the model into your controller.
Controller:
public ActionResult EditingUpdate(MyObject model)
{
string fName = model.FirstName;
....
....
{
Now, the following step is where you have few choices. You can call the controller method in several different ways, all from the gridview partial view. Again, refer to the DevExpress Demo Page. If you want to call the method from an edit action (which is what I assume based on your method name), then you use:
settings.SettingsEditing.UpdateRowRouteValues = new { Controller = "MyController", Action = "EditingUpdate" };
But there are other ways of calling this method, such as
settings.CustomActionRouteValues = new { Controller = "MyController", Action = "EditingUpdate" };
It all depends when you want the gridview to call this method.
Follow the example in the demo, that will help you decide how you want it. Good luck!

Umbraco Surface Controller or RenderMvcController

Hi I have my 'home' controller and a 'sort' controller in umbraco 7. The 'home' controller works fine for the index action as it is overridden from RenderMvcController. Firstly I am confused which controller I should using in which instance i.e a surface controller or a rendermvccontroller. I cant seem to access the twitter action below which is something I need for ajax. Do I need to put the twitter action in a surface controller or could I use a regular mvc controller in umbraco?
public override ActionResult Index(RenderModel model)
{
var storedProcedure = new StoredProcedure()
{
ConnectionString = ConfigurationManager.ConnectionStrings["CentralDbContext"].ConnectionString
};
DataSet ds = storedProcedure.ExecuteProcedureToDataSet("GetHomePage");
IMapSetup map = new MapHomePage();
HomePage homepage = map.Setup<HomePage>(ds);
homepage.Slideshow = CurrentPage.AncestorsOrSelf(1).First().Descendants("SlideshowItem").Take(5).AsMany<Slideshow>();
this._weatherSettings.DefaultLocation = "warrington";
homepage.Forecast = new Forecaster(this._weatherSettings, this._cacheHelper).GetWeather(this._weatherSettings.DefaultLocation);
return CurrentTemplate(homepage);
}
public ActionResult TwitterSort(int? page)
{
int currentPageIndex = page.HasValue ? page.Value - 1 : 0;
var storedProcedure = new StoredProcedure()
{
ConnectionString = ConfigurationManager.ConnectionStrings["CentralDbContext"].ConnectionString
};
DataSet ds = storedProcedure.ExecuteProcedureToDataSet("GetHomePage");
IMapSetup map = new MapHomePage();
HomePage homepage = map.Setup<HomePage>(ds);
if (Request.IsAjaxRequest())
{
return PartialView("umbTweets", homepage.Twitter.ToPagedList(currentPageIndex, DefaultPageSize));
}
return PartialView(homepage.Twitter.ToPagedList(currentPageIndex, DefaultPageSize));
}
My Approach is:
Render controller is only for displaying data to user.
Surface controller is for interaction (I use this for interaction mainly ajax, or forms)
For rendering child action you can use following example:
http://our.umbraco.org/documentation/Reference/Mvc/child-actions
Update:
To implement custom routing you can have a look on
http://cpodesign.com/blog/umbraco-implementing-routing-in-mvc/

ASP.NET MVC Map String Url To A Route Value Object

I am creating a modular ASP.NET MVC application using areas. In short, I have created a greedy route that captures all routes beginning with {application}/{*catchAll}.
Here is the action:
// get /application/index
public ActionResult Index(string application, object catchAll)
{
// forward to partial request to return partial view
ViewData["partialRequest"] = new PartialRequest(catchAll);
// this gets called in the view page and uses a partial request class to return a partial view
}
Example:
The Url "/Application/Accounts/LogOn" will then cause the Index action to pass "/Accounts/LogOn" into the PartialRequest, but as a string value.
// partial request constructor
public PartialRequest(object routeValues)
{
RouteValueDictionary = new RouteValueDictionary(routeValues);
}
In this case, the route value dictionary will not return any values for the routeData, whereas if I specify a route in the Index Action:
ViewData["partialRequest"] = new PartialRequest(new { controller = "accounts", action = "logon" });
It works, and the routeData values contains a "controller" key and an "action" key; whereas before, the keys are empty, and therefore the rest of the class wont work.
So my question is, how can I convert the "/Accounts/LogOn" in the catchAll to "new { controller = "accounts", action = "logon" }"??
If this is not clear, I will explain more! :)
Matt
This is the "closest" I have got, but it obviously wont work for complex routes:
// split values into array
var routeParts = catchAll.ToString().Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
// feels like a hack
catchAll = new
{
controller = routeParts[0],
action = routeParts[1]
};
You need to know what part is what in the catchAll parameter. Then you need to parse it yourself (like you are doing in your example or use a regexp). There is no way for the framework to know what part is the controller name and what is the action name and so on, as you haven't specified that in your route.
Why do you want to do something like this? There is probably a better way.

Asp.net MVC Route Mapping

I have view names like Folder-One/Page-One.aspx I want to do a base controller implimentation that all request go to one Base Controller, that returns the view based on the context. Obviously still keeping the .aspx in the path
I have folders like getting-started/application-faq.aspx but what I want to do is I want to create 1 controller that does all the return views, as the pages are basicly static html
Is this possible?
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{view}.aspx", // URL with parameters
new { controller = "Base", action = "ChooseView" ,view ="Page-One"}
);
and your action can choose view to show :
publict ActionResult ChooseView (string viewName)
{
return View("~/Views/"+viewName);
}

Resources