I am teaching myself asp .net mvc3.
I want to create a user account page which has 3 tabs in it - say YourAddress, YourPhotos and YourProfile.
The 3rd tab (YourProfile) has 2 more subtabs in it ... ChangeDetails and DeactiaveAccount.
They are all dynamic pages and therefore I want to keep them as separate pages.
Basically the urls would be:
localhost/MyHome/YourAddress
localhost/MyHome/YourPhotos
localhost/MyHome/YourProfile/ChangePassword
localhost/MyHome/YourProfile/DeactivateAccount
(As requested I have changed the generic tab1, tab2 etc to something in real-world scenario)
I am planning to do something like this:
public class MyHomeController : Controller
{
//
// GET: /MyHome/Tab1
public ActionResult Tab1()
{
return View();
}
//
// GET: /MyHome/Tab2
public ActionResult Tab2()
{
return View();
}
//
// GET: /MyHome/Tab3
public ActionResult Tab3()
{
return View();
}
}
How do I handle the subtabs of YourProfile? How do I call a controller within a controller?
What is the best way to accomplish this.
Thanks
Have separate action method for each tab item in your controller.
public class MyHomeController : Controller
{
public ActionResult YourAddress()
{
return View();
}
public ActionResult YourPhotos()
{
return View();
}
public ActionResult YouProfile()
{
return VieW();
}
public ActionResult ChangePassword()
{
return View();
}
public ActionResult DeActivate()
{
return View();
}
}
For the sub tab content, define that route in the global.asax
routes.MapRoute("ChangePass","YourProfile/ChangePassword",
new { controller="MyHome", action="ChangePassword" });
routes.MapRoute("DeActivate","YourProfile/DeActivate",
new { controller="MyHome", action="DeActivate" });
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional });
Always use Url.Action Html Helper method to render a path to an action method.
<div id="tabs">
<ul>
<li>Address</li>
<li>Photos</li>
</ul>
</div>
Related
I have a couple of controllers like this:
[RoutePrefix("side-navigation")]
public class SideNavigationController : BaseController
{
[Route("{pathname}")]
public ActionResult Index(string pathname)
{
SideNavigationPopoutModel model = _sideNavFactory.Value.CreatePopout(pathname);
if (model != null)
{
return View(model);
}
return HttpNotFound();
}
}
public class CatchAllController : BaseController
{
public ActionResult Index(string pathname)
{
CatchAllModel model = _catchAllModelFactory.Value.Create(pathname);
if (model != null)
{
// TODO: Do we need this - what does it do?
// TempData.Restore(this);
return View(model);
}
return HttpNotFound();
}
}
But I cannot seem to get to my index action in the side navigation controller - if I browse to localhost/side-navigation/test it's hitting the catch all controller with side-navigation/test as it's pathname instead of the side navigation one with test as the pathname.
Can anyone see anything I am doing wrong here or how to make the side navigation controller work?
This is the route config:
// MVC attribute routing
routes.MapMvcAttributeRoutes();
// Default catch all route
routes.MapRoute(
"Default",
"{*pathname}",
new { controller = "CatchAll", action = "Index" });
Weirdly, if I change the route of the side navigation index to test/{pathname} and browse to side-navigation/test/test it will work and the controller will be hit but I don't want to add anything before the pathname
It seems that you are not using [Area] also put attribute [Route("[action]")] above method.
Ok I have fixed this by adding an asterisk before the pathname:
[RoutePrefix("side-navigation")]
public class SideNavigationController : BaseController
{
[Route("{*pathname}")]
public ActionResult Index(string pathname)
{
}
}
If anyone can explain why this works and without an asterisk doesn't, it would be greatly appreciated, as I also have a product controller set up in exactly the same way that doesn't need the asterisk
[RoutePrefix("side-navigation")]
public class SideNavigationController : BaseController
{
[Route("{*pathname}")]
public ActionResult Index(string pathname)
{
}
}
I currently have a Products controller with a hardcoded 'Product' actionresult per product (as the products are fixed and do not change):
site.com/Products/Product
site.com/nl/Products/Product
This results in a single page per product containing all information.
Now I would like to create multiple pages per product to highlight some features or options instead of showing a single product page.
e.g.:
site.com/nl/Products/Product/Detail1
site.com/nl/Products/Product/Option2
site.com/nl/Products/Product/Option16
What is the best way to do this?
Should I create e.g. ProductDetail1 action and a ProductOption2 action?
You can responce different views in a single action
public class ProductsController : Controller
{
public ActionResult Product(int id, string view,)
{
Product prod = Context.GetProduct(id);
if(!string.IsNullOrEmpty(view))
{
switch(view.ToLower()){
case "detail": return View("Detail", prod.Detail);
case "option1": return View("Option1", prod.GetOption(1));
case "option2": return View("Option2", prod.GetOption(2));
}
}
return View();
}
}
Well you have your Controller Method:
public class ProductsController : Controller
{
public ActionResult Product(string option)
{
//here your logic
return View();
}
}
You can change your Default Route:
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{option}",
defaults: new { controller = "Home", action = "Index", option = UrlParameter.Optional }
);
Now if you call url like site.com/nl/Products/Product/Detail1 option object in your controller will have value Detail1. And you can do anything what whould you like with this param.
Am new to MVC ASP.Net. I would like to call an action method from another controller and use a different layout page.
My Views/Shared folder has two layout pages: ~/Views/Shared/_Layout1.cshtml and ~/Views/Shared/_Layout2.cshtml. Below is my code:
//HomeController
public class HomeController : Controller
{
public ActionResult Index(string id)
{
if(String.IsNullOrEmpty(id))
{
//Call someMethod from UserController
//And when called, it should a different Layout page: ~/Views/Shared/_Layout2.cshtml
return View("someMethod");
}
else
{
return AboutPage(id); //uses ~/Views/Shared/_Layout1.cshtml
}
}
public ActionResult AboutPage(string id)
{
return View();
}
}
If you want to use different layout then you can use overloaded version of View method:
return View("view", "_Layout1");
If you want to redirect control flow to different controller/action then:
return RedirectToAction("action", "controller");
So I am a little confused as to how to handle some MVC Routing
I have an AdminController
public class AdminController : Controller
{
//
// GET: /Admin/
public ActionResult Index()
{
return View();
}
public ActionResult Users()
{
return View();
}
public ActionResult Books()
{
return View();
}
}
Which works fine. So I can go to /Admin/Books
This is the admin menu for managing books. Now in there I'd like to be able to route like
/Admin/Books/ViewBook/10
or
/Admin/Books/Add
Something like that. I can't seem to grasp how to route these things that way.
I made a controller
AdminBookController
public class AdminBooksController : Controller
{
//
// GET: /AdminBooks/
public ActionResult List()
{
return View();
}
public ActionResult Add()
{
return View();
}
[HttpGet]
public ViewResult BookDetails(Guid guid)
{
return View();
}
[HttpPost]
public ViewResult BookDetails(ModifyBook Book)
{
if (ModelState.IsValid)
return View("Book successfully Edited!");
else
return View();
}
}
}
but I don't want it to be /AdminBooks I feel like /Admin/Books/Action/Param is much nicer.
Thanks in Advance!
If you want those urls to map to your AdminBooks controller, you'll need to map the following routes (in this order):
// maps /Admin/Books/ViewBook/{id} to AdminBooksController.BookDetails(id)
routes.MapRoute(
"AdminBooks_ViewBook", // Route name
"Admin/Books/ViewBook/{id}", // URL with parameters
new { controller = "AdminBooks", action = "BookDetails", id = UrlParameter.Optional } // Parameter defaults
);
// maps /Admin/Books/{action}/{id} to AdminBooksController.{Action}(id)
routes.MapRoute(
"AdminBooks_Default", // Route name
"Admin/Books/{action}/{id}", // URL with parameters
new { controller = "AdminBooks", action = "List", id = UrlParameter.Optional } // Parameter defaults
);
Note: be sure to put these mappings before the default MVC route.
Consider creating an Admin Area and adding a BookController to that Area. See the following link for a walkthrough:
http://msdn.microsoft.com/en-us/library/ee671793.aspx
You can add a new route in your Global.asax file.
See this question:
Use MVC routing to alias a controller
I was under the impression that every View in your application has it's own unique URL. For example:
Home/Index
Home/Test
Home/Error
Home/Help
In my Upload controller I call on the Error view. Yet the URL stays on what it was before, not changing to reflect the error url.
[HttpPost]
public ActionResult Index(HttpPostedFileBase excelFile)
{
if (excelFile != null)
{
*Snip for brevity, everything is peachy here.*
return View();
}
else
{
return View("Error");
}
}
Any suggestions why this is the case?
Shouldn't the URL be /Upload/Error? Thank you for your help. :)
URLs do not map to Views.
URLs map to Controller actions.
See this http://weblogs.asp.net/scottgu/archive/2007/12/03/asp-net-mvc-framework-part-2-url-routing.aspx
If you want a URL of /Upload/Error
You could make:
public ActionResult Error()
{
return View();
}
[HttpPost]
public ActionResult Index(HttpPostedFileBase excelFile)
{
if (excelFile != null)
{
*Snip for brevity, everything is peachy here.*
return View();
}
else
{
return RedirectToAction("Error","Upload");
}
}
You are returning the content of the View. If you want the URL to change, you need to RedirectToAction()
If you want the URL to change to /Upload/Error, here's what you would add to your UploadController:
public ActionResult Error()
{
return View();
}
Then, instead of returning the Error view, you would call: return RedirectToAction("Error","Upload");.
This basically shows the difference between controllers, actions, and views - controller actions can return any view they want (or other ActionResult) to a request, but only on one URL, unless they "reroute" the request to another action.
In ASP.NET MVC every URL maps to a controller/action. So you can return whatever view from your controller action, this doesn't change the URL.
If you want to redirect to an error Page, then either include a ErrorController in your project or an Error action in your FileUploadController and then do a Redirect to the appropriate action:
public class ErrorController : Controller
{
public ActionResult FileUploadError()
{
return View(); //returns view "FileUploadError"
}
}
public class FileUploadController : Controller // the controller you use to upload your files
{
public ActionResult Error()
{
return View(); //return view "Error"
}
public ActionResult Index(HttpPostedFileBase excelFile) // action from your post
{
//... do the upload stuff
else
{
return RedirectToAction("Error"); // if you want to use the Error action in this controller;
// or
return RedirectToAction("FileUploadError", "Error"); // if you want to use the action on the ErrorController
}
}
}