In my app I am creating a dynamic menu. The menu is populated depending upon the controller it is called for. For example in one of my Controller name is Organization. To populate the menu for it I call this
#Html.Action("Menu","Site", new { calledForController = "Organization", oId = #Model.Id })
Everything is working nice and smooth but the issue I am experiencing as I am having more views is that I have to put the above line in every view. What I am looking for is a way to get the current controller and action name from the route data so that I don't have to call this on every view.
The ideal solution would be to write something like this
#Html.Action("Menu","Site")
in my _Layout.cshtml and then in the menu controller populate menu list depending upon where it was called from.
If I write
this.ControllerContext.RouteData.Values["controller"].ToString();
in my Menu action of Site controller I am always getting Site as my controller name. Any thoughts on this?
I have searched and found this as an appropriate solution for me, to get the Route data use this
var routeValues = HttpContext.Request.RequestContext.RouteData.Values;
if (routeValues.ContainsKey("id"))
oId = (String)routeValues["id"];
This way in my _Layout.cshtml I can write this
#Html.Action("Menu","Site")
And now I don't have to pass in extra called for controller again and again.
Related
I'm using ASP.NET MVC in Visual Studio 2015. The app has the following structure:
MyApp
Controllers
Controller1
Actions
Create
Delete
Details
Edit
IndexPartial
Controller2
Actions
Edit
Controller3
Actions
Edit
Views
Controller1
Create
Delete
Details
Edit
IndexPartial
Controller2
Edit
Controller3
Edit
The app displays Controller1/IndexPartial view on the Controller2/Edit view and on Controller3/Edit. This partial view displays rows of data, each with Edit, Details, Delete buttons which take the user to the Controller1 views for those actions.
When the user is done with the Controller1 action, they need to return to Controller2/Edit or Controller3/Edit via the Back to List button or when the Save/Delete buttons are clicked. But how do we determine where the user originated? Did the user come from the Edit of Controller2 or Controller3?
We've thought of using a session variable. Can RouteConfig.cs be used to track the user's path and help determine where s/he should return? How do we do this via routes in MVC?
Thank you for your help.
Update: This is all done via the server; no JavaScript (Angular, etc.).
The routing engine has nothing to do with what you need. You need to track user navigation and a good way to do this is using ActionFilters.
You can create a custom ActionFilter that checks the UrlReferrer on its OnActionExecuted and decides how to redirect the request to the appropriate Controller/Action.
[Example]
ActionFilter
public class RedirectAfterActionFilter : ActionFilterAttribute, IActionFilter
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
// Your decision logic
if (filterContext.HttpContext.Request.UrlReferrer.AbsolutePath == "something usefull")
{
filterContext.Result = new RedirectToRouteResult("Your Route Name", routeValues: null); // redirect to Home
}
base.OnActionExecuted(filterContext);
}
}
ActionFilter usage
[RedirectAfterActionFilter]
public ActionResult DoSomethingAndGetRedirected()
{
// Save, Edit or Whatever
//...
return new EmptyResult(); // no need to return since the user will be redirected by the filter
}
Extra: Read How to redirect from a action filter if you dislike to use Route names to redirect.
There are two aspects to this:
The "Back to List" link
The "Save/Delete" actions
As far as the "Back to List" link, your controller should be giving the view all the information it needs to produce a viable GUI. Pass an identifier (or even the actual return URL) to the view in the ViewBag as a dynamic property and let the view render the link to the destination.
For the "Save/Delete" actions, it depends on how they are implemented.
If it's all JS with http requests then the same concept above applies.
If you are posting back to the server however, the controller will have to do the redirection with something like RedirectToAction().
How about storing the previous location in a ViewBag and then populate your button href with the ViewBag content...
Or
You can use Url Referrer, which fectches the previous url that linked to current page.
Of course the best method will depend on your implementantion, without seeing your code those two are the best option that I can think of.
I'm totally new to MVC. Now I'm trying to create a View in the folder Sample( which is under the folder of Views). I right-clicked the Sample folder and selected "Add View", then hit the view name as Test. After the view has been created, I typed in following code:
<!DOCTYPE html>
<html>
<head>
<title>Sample View</title>
</head>
<body>
<p>
Test
</p>
</body>
</html>
Build. Then I tried to navigated the address http://localhost:24694/Sample/Test in my browser. But the browser read "The resource cannot be found.". Why? I've also other cshtml files in the Sample folder(which was generated by others), they worked fine. For example, there is a file called "Message.cshtml" under the folder of Sample, and I can navigate the address http://localhost:24694/Sample/Message with ease. Is there anything that I should add?
3 Step Process
1 - Define the Route
routes.MapRoute("Test", "test",
new { controller = "NameOfController", <- In your case TestController
action = "Index", <- Name of action in controller returning view
parameter = "parameterName - leave empty if no params needed"
});
2 - Create the controller
So if you follow the above method and call your route Test and the view Test then you need to create the controller called TestController. MVC automagically sows these together thanks to your route config you did earlier (RouteConfig.cs)
3 - View
In your case you just make sure the view is returning something.
Easy as that. Good luck.
you cannot use
http://localhost:24694/Sample/Test
to navigate to view because you can only access a view through a controller. so follow these steps
First of all create a new controller inside controllers folder and name it 'SamplController'.
By default there will be an action method named Index().
Create a new Action method named 'Test' inside 'SampleController'
Now right click inside 'Test' action method and click on Add View. it will add a new view insides Views folder named 'Test.cshtml'. You can use it. if you want to place this View inside other folder then you've to modify the return statement of 'Test' action method. For example you created a folder 'MyViews' inside Views folder and moved 'Test.cshtml' there. Now your return statement in 'Test' action method will be like this
return View("~Views/Sample/MyViews/Test.cshtml");
instead of
return View();
Now when you use
http://localhost:port/Sample/Test
it will create a new instance of 'Sample' Controller and will call 'Test' action method. This method will return specified view. i hope it will help :)
ASP.NET MVC is based on routing not in file system like asp.net webforms. Following the internals, views should be in the Views folder from the ASP.NET MVC application template, like Controllers should stay on the Controllers folder. It is not required, but it is setted by default from asp.net mvc framework.
In your a Controller (class), you could have some Actions (methods), which can return a view, image, file, etc, implementations that derive from ActionResult type. Theses actions, could return a view using the View method from the controller base class. By default, the asp.net mvc will search for a view (.cshtml or .aspx file) inside the ´Views` folder and in a folder with the same name of the Controller, for sample, if you have a controller like this:
public class ProductController : Controller
{
public ActionResult Index()
{
return View();
}
}
It will find a view in Views/Product/Index.cshtml and render it for you. I recommend you reading more in http://asp.net/mvc
I've created a controller, called ClientController.cs and VS automatically created the necessary View files in /Views/Client. But I wanted to get these pages in a different URL... So, it is /Client but I need it at /admin/client.
What should I change?
Thank you!
It's not clear what your functionality will be in the long run, but here are a few options that allow you to get the URL format you want:
Perhaps you want a controller called "Admin" and an action called "Client". This would give you a path of /Admin/Client by default
Alternatively, you can change your route maps. For example, the following with route /Admin/Client to the Index of your Client controller:
routes.MapRoute(
"Default", // Route name
"Admin/Client/{action}", // URL with parameters
new { controller = "Client", action = "Index" } // Parameter defaults
);
Or maybe even go a far as using "Areas", depending on what you need. Have a Google of that if you're interested in learning more
If you want it to be admin/client, then using the default routing you should create an Admin Controller with an ActionResult method called Client. Your views folder should have an admin folder with your client view inside.
I haven't done a lot of MVC but i believe this is what you do.
This is a very basic question, yet I cannot find any clear, simple, direct answers.
I have a basic MVC4 app with 1 HomeController.cs file. I want to create a second Controller.cs file to put more code into so HomeController doesn't turn into spaghetti code.
So obviously step 1 is to add a new controller. I assume the next step is to add some stuff to RouteConfig.cs.
What do I need to add to RouteConfig.cs to utilize a new Controller.cs?
You shouldn't need to add anything. HomeController requires a line of code in your RouteConfig to be set as the default controller (for when users navigate to the site root), but any other controller should be accessible with the default routing.
Just create a controller, add some actions, and you should be able to route to it with the format Controller/Action or using the routing helper functions.
What does your routes file look like?
Normally, there's a default route:
routes.MapRoute("default",
"{controller}/{action}/{id}",
new { controller = "Home", action="Index" }
);
That means that so long as you add a new controller with the Controller suffix, MVC will make sure the routing engine sees your controller, and as long as your URL follows the above structure, requests made in that format will be routed to the appropriate controller.
We normally send it to a different view which submits to different controllers, or add a reference in your current controller if your just wanting to call certain methods in your current home controller.
What you really need first after creating a new controller is to add a new action (if it's not added automatically) and then add a new View for your new action.
You need to touch your routes only if you are about to process some specific parameters which dont match your default settings
Now, the question. I have an eCommerce website and I have a controller called Store with an action Index. When someone types www.mysite.com/sony, I want to route to controller Store and action Index with parameter brand=Sony. If someone type www.mysite.com/sony-tv, I want to route to controller Store and action Index but with the parameters brand=sony and department=tv.
I obtained that by creating a route for every situation storing in a database, and building the routes dynamically when the app starts. Its works fine in a few cases.
First, i need to index the routes. I need to map the route sony-tv before the sony, otherwise the /sony-tv maps to /sony equally.
When i enter at site's home (www.mysite.com) and click at Url.Action("Index","Store", new {brand=Sony}) it route me to www.mysite.com/sony. NICE!. Now, inside the SONY brand i'll click at Url.Action("Index","Store", new {brand=sony, department=tv}) and I can see all TV's from Sony.
Everything is running fine until here. In the database, I have 1 route to /sony where I say i have a parameter named brand with value Sony and a constrained named brand with value Sony. I have another route saying the same way to sony-tv. The pattern sony-tv has a parameter named brand with value sony and a parameter named deparment with value tv, and the sames constraints of parameters.
In my head, its means that the route for www.mysite.com/Sony is Store/Index/brand=sony and the www.mysite.com/sony-tv is Store/Index/brand=sony&department=tv. With the constraints, i understand that if department is not TV or if the parameter department does not exists, it will send to www.mysite.com/sony
When i'm at www.mysite.com/sony-tv, if I pass my mouse over the other brands, the link build to Url.Action("Index","Store", new {brand=Apple}) is www.mysite.com/Apple-Tv
I have a route to Apple-TV equal to Sony. The URL exists but i'm not passing the TV parameter. I passed on this link (brands links) only the brand. I want to move the user to brand's root he's moved to brands + department.
I don't know, its looks like the department variable is passing through again and I don't know how to cancel that.
I'm completely wrong? What i'm doing is valid? I can do that? Where is my mistake?
At cshtml file:
#Html.ActionLink(febrand.Name.ToUpper(), "Index", new { controller = "Store", brand= febrand.FriendlyName, department = string.Empty })
at final html file (show source code from google chrome):
SONY
Fisrt, that seems like a lot of work for something that you could do with two custom routes. Additionally, as your route table gets larger (eg. adding more brands and/or departments), each request to your site will take longer to fulfill due to having to scan a larger list of routes.
So, lets attempt to fix your route table. Place these two routes above your default route in the global.asax:
routes.MapRoute(
"Department",
"{brand}-{department}",
new { controller = "Store", action = "Index" };
routes.MapRoute(
"Brand",
"{brand}",
new { controller = "Store", action = "Index" });
As for your issue, when you create your action link, the routing engine is holding onto the department route value from the view you are currently on. To make it forget that parameter when generating a link, send a null across for the department variable when you do not need it.
#Html.ActionLink("Apple", "Index", new{controller="Store", brand="Apple", department = string.empty});
EDIT
I feel you may be in a weird edge case with your routing (and there are numerous examples of this problem all across SO, such as here and here). The solution, other than the one I provided, is to switch to Html.RouteLink instead of Html.ActionLink.
RouteLink Signature that we are going to use
Html.RouteLink(string linkText, string routeName, object RouteValues)
Example Brand link for your code
#Html.RouteLink(febrand.Name.ToUpper(), "Brand", new { controller = "Store", action = "Index", brand= febrand.FriendlyName})