Reusing controllers - asp.net-mvc

Is it possible to re-use controllers in ASP MVC? And if so how?
Perhaps re-use isn't the right word. The situation is I have a menu and sub menu navigation bars as shown below (actually there is another nav bar what is shown)- I know the colour scheme needs some work
The upper bar is populated from a database, so there could be more or less than 3 plans.
The lower bar always has the same three entries. The views for each of these entries are the same regardless of which plan is selected, though they are different from each other. Obviously the data within them is different (populated from different tables).
That is Plan A -> Suggested Points view is the same as Plan B -> Suggested Points view.
But Plan A -> Suggested Points view is not same as Plan A -> Accepted Points view
In order to do this with the views I intend to use partial views, so the same view files can be re-used.
However, how can I do the equivalent for the controllers?
What I would like if for url paths such as:
/PlanA/SuggestedPoints
/PlanB/SuggestedPoints
To my mind I just want the Plan links to set a variable that tells the Points views which database they should hook up to. Which may be the wrong way to think of it and I suspect is incompatible with the url path suggestion above.

Suggested Approach
I would suggest it is better to include a controller name in the route, that way you won't get conflicts so easily with other controllers in your app.
You can modify your RouteConfig.cs file and map a new route. Make sure to add the custom route before the "Default" one.
Something like this:
routes.MapRoute(
"Plans",
"Plans/{planName}/{action}",
new { controller = "Plans", action = "Index" }
);
// Default route here.
Then you would have a controller called Plans with each of your actions having a parameter called planName that lets you identify with plan to work with...
public class PlansController : Controller
{
public ActionResult SuggestedPoints(string planName)
{
// create your view here, using the planName to get the correct data.
}
public ActionResult AcceptedPoints(string planName)
{
// create your view here, using the planName to get the correct data.
}
// etc.
}
This method will allow URL's in the following format:
/Plans/PlanA/SuggestedPoints, /Plans/PlanA/SuggestedPoints, /Plans/PlanB/AcceptedPoints, /Plans/PlanB/AcceptedPoints, etc.
NOTE: If your plans are in your database, it may be more beneficial to use an ID for the plan, but the URL's would look less friendly so that is up to you.
Finally, when you want to create your links in your view, you can use the following:
#Html.RouteLink("link text", "SuggestedPoints", new { controller = "Plans", planName = "PlanA" })
Your Exact Request
If you absolutely must use the URL formats you suggested, then you can do the following which requires a route for each action, but be wary that you will need to rely on the uniqueness of the Action names to ensure they don't conflict with other controllers...
routes.MapRoute(
"SuggestedPoints",
"{planName}/SuggestedPoints",
new { controller = "Plans", action = "SuggestedPoints" }
);
routes.MapRoute(
"AcceptedPoints",
"{planName}/AcceptedPoints",
new { controller = "Plans", action = "AcceptedPoints" }
);
routes.MapRoute(
"RejectedPoints",
"{planName}/RejectedPoints",
new { controller = "Plans", action = "RejectedPoints" }
);
// Default route here.
In this instance, the controller will remain the same as my first suggestion above. Which will allows URL's like as follows:
/PlanA/SuggestedPoints, /PlanA/SuggestedPoints, /PlanB/AcceptedPoints, /PlanB/AcceptedPoints, etc.

It can be something like this:
public class PlanController
{
public ActionResult SuggestedPoints(string plan) //or int planID
{
return View();
}
public ActionResult AcceptedPoints(string plan) //or int planID
{
return View();
}
public ActionResult RejectedPoints(string plan) //or int planID
{
return View();
}
}
and example urls next:
/Plan/SuggestedPoints/PlanA
/Plan/AcceptedPoints/PlanB

Related

MVC creating 'folders' and sub-folders

In ASP.NET WebForms (well, HTML to be honest) we could reference pages within folders. EG, my structure could be (in regards to folders only)
root -> MyProductsFolder -> Shoes -> Ladies
And my website would show
www.mysite.com/MyProducts/Shoes/Ladies/Page.aspx
In MVC, we use a controller and it would appear that we can only ever have 1 level (folder) deep.
Is this right?
Without using URL rewriting, is it possible to have
www.mysite.com/MyProducts/Shoes/Ladies/Page
I assume the only way to do this is in the controller, but I can't create a controller named Shoes/Ladies
You can use MVC routing to created this URL. Your routing table is usually found in your AppStart > RouteConfig.cs class. You can use the route table to create URL maps to your actions in your controllers.
Assuming that MyProducts is your controller, and Shoes, Ladies are variables you want to accept you can do something like:
routes.MapRoute("MyProducts",
"MyProducts/{category}/{subcategory}/Page",
new { controller = "MyProducts", action = "Index" });
Note that your routes should be in order of most to least specific, so add this route above the default route.
When you navigate to /MyProducts/Shoes/Ladies/Page, it will map to your index action result in your MyProducts controller, passing variables for category and subcategory, so your controller will look something like
public class MyProducts : Controller
{
public ActionResult Index(string category, string subcategory)
{
//Do something with your variables here.
return View();
}
}
If my presumption is wrong, you want a view returned just for that URL, your route will look like:
routes.MapRoute("MyProducts", "MyProducts/Shoes/Ladies/Page", new { controller = "MyProducts", action = "LadiesShoes" });
And your Controller:
public class MyProducts : Controller
{
public ActionResult LadiesShoes()
{
//Do something with your variables here.
return View();
}
}
You can safely omit the final "/page" on the URL if you want to.
If I haven't covered your exact scenario with the above examples, let me know and I will extend my answer.
UPDATE
You can still put your views in a folder structure under the views folder if you want - and then reference the view file location in the controller - in the following example, place your view file called Index.cshtml in Views/Shoes/Ladies/ folder:
public class MyProducts : Controller
{
public ActionResult LadiesShoes()
{
//Do something with your variables here.
return View("~/Views/Shoes/Ladies/Index.cshtml");
}
public ActionResult MensShoes()
{
//Do something with your variables here.
return View("~/Views/Shoes/Mens/Index.cshtml");
}
}
You can use Attribute Routing to define the url of each action like below.
public class ShoeController : Controller
{
// eg: /nike/shoes/lady
[Route("{productName}/shoes/{xxx}")]
public ActionResult View(string productName, string xxx)
{
}
}
Routing Attribute offers flexibility and better code organization. You can check the route definition in the same spot.

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!

How can I set up a simple route with areas in ASP.NET MVC3?

I want to use Areas so I set up the following:
public class ContentAreaRegistration : AreaRegistration
{
public override string AreaName
{
get
{
return "Content";
}
}
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Content_default",
"Content/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional }
);
}
}
What I would like is for a person who enters the following URL to be directed to a controller inside my Content area.
www.stackoverflow.com/Content/0B020D/test-data
I would like a person entering any URL with "/Content/" followed by six characters to be sent to:
- Page action in a controller named ItemController
- Six characters passed as the parameter id
- Optional text after that (test-data in this case) to be put into parameter title
How can I do this? I am not very familiar with setting up routes when using areas.
the six digits to be put into a variable called ID
So you're looking for something like
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Content_default",
"Content/{id}/{optional}",
new { controller = "ItemController", action = "TheActionYouWantThisToAllRouteTo" }
}
This would default everything to one controller and action method (which you have to specify in your instance). You can then get the data like so:
public ActionResult TheActionYouWantThisToAllRouteTo (string id, string optional)
{
// Do what you need to do
}
The way the routes are setup, you can name the pieces of information you want in a URL by wrapping it in a pair of { } curly braces. If you'd rather the name of optional to be isTestData then you would just change the route to read "Content/{id}/{isTestData}".
Note: Since you didn't specify the default action method you want this to route to, I substituted it with TheActionYouWantThisToAllRouteTo. Change that string to read the action method you want this to all go to. This also means you can't have a "regular" controller named ContentController, either.
Edit
Stephen Walther has a good blog post on custom route constraints. It can be found here. It should be a good start to get done what you need.

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.

Advanced Routing Behaviour with ASP.NET MVC Routing

Given a url that follows the following pattern:
firstcolor={value1}/secondcolor={value2}
where value1 and value2 can vary and an action method like:
ProcessColors(string color1, string color2) in say a controller called ColorController.
I want the following route evaluation:
URL '/firstcolor=red' results in a call like ProcessColors("red", null)
URL '/secondcolor=blue'results in a call like ProcessColors(null, "blue")
URL 'firstcolor=red/secondcolor=blue' ends up in a call like ProcessColors("red", "blue")
Now from I think this can be achieved with a few routes, something like this
route.MapRoute(null,
"firstcolor={color1}/secondcolor={color2}",
new { controller=ColorController, action = ProcessColors })
route.MapRoute(null,
"firstcolor={color1}}",
new { controller=ColorController, action = ProcessColors, color2 = (string)null })
route.MapRoute(null,
"secondcolor={color2}}",
new { controller=ColorController, action = ProcessColors, color1 = (string)null })
This is sufficient for just 2 colors, but as far as I can tell we'll end up with a proliferation of routes if we wanted to have, say 4 colors and be able to have URL's like this:
'/firstcolor=blue/secondcolor=red/thirdcolor=green/fourthcolor=black'
'/firstcolor=blue/thirdcolour=red'
'/thirdcolour=red/fourthcolour=black'
and so on, i.e. we need to cater for any combination given that firstcolor will always be before 2nd, 2nd will always be before 3rd and so on.
Ignoring my ridiculous example, is there any nice way to deal with this sort of situation that doesn't involve lots of routes and action methods needing to be created?
First of all, if you are going to use that key=value format, then I suggest using QueryString instead of the URL.
But if not, you can do this :
//register this route
routes.MapRoute("color", "colors/processcolors/{*q}",
new { controller = "Color", action ="ProcessColors" });
Then in your ColorController :
public ActionResult ProcessColors(string q) {
string[] colors = GetColors(q);
return View();
}
private string[] GetColors(string q) {
if (String.IsNullOrEmpty(q)) {
return null;
}
return q.Split("/".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
}
In this case your URLs will be like this :
site.com/colors/processcolors/red
site.com/colors/processcolors/red/green
In the case that we use the wildcard mapping I suppose we lose the ability to use Html.ActionLink to build our URL's for us?

Resources