I have an issue, when I'm trying to build the url for action in controller, the value of vm after assigning is "/". If I try to create url with other action name then everything works fine, like Url.Action("Edit", "Contact").
public class ContactController : Controller
{
public ActionResult List()
{
string vm = Url.Action("Create", "Contact"); // equals "/"
string editUrl = Url.Action("Edit", "Contact"); // all is fine
return View("List", vm);
}
public ActionResult Create()
{
return HttpNotFound();
}
public ActionResult Edit()
{
return HttpNotFound();
}
}
What's wrong with that code?
It is because your route specifies them as defaults.
Your route is:
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Contact", action = "Create", id = String.Empty }, null);
Essentially, it is because you specify the default values controller = "Contact", action = "Create". When you specify these as default you are saying if the value is not provided in the URL then use these.
For examples all these URLs are the same: /, /Contact & /Contact/Create. By default MVC generates you the shortest URL.
You could either change the default values or remove them like this:
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { id = String.Empty }, null);
Related
I have 2 controllers:
public class HomeController : Controller
{
public ActionResult Index(string id) //id is category slug
{
if(string.IsNullOrEmpty(id))
id = "MainCategory";
var model = getCategoryPageModel(id);
return View(model);
}
}
public class PostController : Controller
{
public ActionResult Index(string id) //id is post slug
{
var model = getPostModel(id);
return View(model);
}
}
And this is my route config:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
//angular route for admin section
routes.MapRoute(
name: "AngularCatchAllRoute",
url: "Admin/{*any}",
defaults: new { controller = "Admin", action = "Index"}
);
//route which includes language
routes.MapRoute(
name: "DefaultLocalized",
url: "{lang}/{controller}/{action}/{id}",
constraints: new { lang = #"(\w{2})|(\w{2}-\w{2})" }, // en or en-US
defaults: new { controller = "Home", action = "Index", id = "" }
);
//do I need this one??
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
I want to have two types of custom routes:
www.mysite.xyz/categoryName - calls Home/Index/id with default language ('sr')
www.mysite.xyz/en/categoryName - calls Home/Index/id with language 'en'
www.mysite.xyz/Post/postID - calls Post/Index/id with default language('sr')
www.mysite.xyz/en/Post/postID - calls Post/Index/id with language 'en'
My 'DefaultLocalized' route already works fine with default and custom language route part, but my url has to contain all route parts: controller/action/id. I just want to simplyfy urls to be more readable to users.
Actually I made it work for post with 'lang' to be mandatory:
www.mysite.xyz/sr/Post/postID - but I want 'sr' to be default like in 'DefaultLocalized' route, there I don't have to set lang to be 'sr'...
I already have tried some answers from other similar questions but I did not make it work.
You can use attribute routing as below:
[Route("~/{cate}")]
[Route("{lang}/{cate}")]
public IActionResult Index(string lang, string cate)
{
return View();
}
That work for me with urls:
http://[host]/Mobile
http://[host]/en/Mobile
Hope this help!
I have a bunch of mostly-static pages (about 40),
like: order-form01.html, order-form02.html, orderform03.html etc..
Should each of them have its own Controller/Action, or is that possible to have one dynamic Controller/Action for all of them?
My Url should look like this: http://MyProject/GlobalController/IndividualView and for the above example: http://MyProject/OrderForm/order-form01, http://MyProject/OrderForm/order-form02 etc..
Thanks in advance.
Yes it's very easy AND you don't need a switch statement or any other redundant logic.
public class MyController
{
public ActionResult Page(string file)
{
return View(file);
}
}
The magic is in the Route Map:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
// New MapRoute for your 40+ files..
routes.MapRoute(
"OrdeForm",
"OrderForm/{file}",
new { controller = "MyController", action = "Page", {file} = "" }
);
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = "" }
);
}
Additionally:
I pass the View name in the query string.
Is not required, but is supported. The following urls will work:
// Url Parameters
http://MyProject/OrderForm/order-form01
http://MyProject/OrderForm/order-form02
// Querystring Parameters
http://MyProject/OrderForm?file=order-form01
http://MyProject/OrderForm?file=order-form02
The only catch is that you need to rename your html files to cshtml and place them in the correct directory for the ViewEngine to find.
#Erik, I also bit of new to mvc . Could you please explain your route map as of how is it possible with default raute again and again
Routes are broken down into 3 values:
Controller
Action
Parameter(s)
At a bare minimum, the controller and action are required. Where the values come from is not dependent on the Url. For example, in the following Url and Map Route...
// Url
http://MyProject/
// MapRoute
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = "" }
);
// Controller named "Home" matches the default in the above route
// Method named "Index" matches the default in the above route
public class HomeController {
public ActionResult Index() {
return new EmptyResult();
}
}
... everything still works because we provided a default value for the controller and action.
Ok let's break down the URL you want:
http://MyProject/OrderForm/order-form01
http://MyProject/OrderForm/order-form02
http://MyProject/<identifier>/{parameter}
You have one identifier that tells me route (OrderForm) and one changing value that because it changes and you want one value, should be a parameter.
http://MyProject/<identifier>/{file}
The name of the parameter makes no difference as long as it matches the signature of the controller method:
http://MyProject/{Controller}/{file}
public class HomeController {
public ActionResult Index(string file) {
return new EmptyResult();
}
}
or
http://MyProject/{Controller}/{einstein}
public class HomeController {
public ActionResult Index(string einstein) {
return new EmptyResult();
}
}
I named the parameter file, because it tells me it's the parameter is a name of a file, whereas the name einstein has no inherent description so is a terrible name for a variable.
http://MyProject/{Controller}/{file}
// MapRoute
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = "" }
);
// Controller named "Home" matches the default in the above route
// Method named "Index" matches the default in the above route
public class HomeController {
public ActionResult Index() {
return new EmptyResult();
}
}
Now we only want this route to run when the identifier is OrderForm so we don't allow that to be a value, we hard code it.
url: "OrderForm/...
Next we have a value that keeps changing, so we to add url parameter:
url: "OrderForm/{file}"
Now we have an issue because we aren't allowing MVC to parse values from the url to populate Controller nor Action so we must supply them.
routes.MapRoute(
name: "",
url: "OrderForm/{file}",
defaults: new { controller = "Home", action = "Index", file = "" }
);
Here we've mapped the url http://MyProject/OrderForm/{file} to:
public class HomeController {
public ActionResult Index(string file) {
return new EmptyResult();
}
}
Now I would choose to to update the defaults to something more specific and descriptive:
routes.MapRoute(
name: "",
url: "OrderForm/{file}",
defaults: new { controller = "OrderForm", action = "Index", file = "" }
);
public class OrderFormController {
public ActionResult Index(string file) {
return new EmptyResult();
}
}
Hope that all makes sense.
After the question edited :my solution is, you can have one controller/action and it should call view (cshtml). Your querystring data should be pass to view as of viewbag variable and partial views should be called acording to the viewbag variable. noo need of editing routing table even(if you are willing to pass it as a query string).
//your routeconfig will be
routes.MapRoute(
name: "default",
url: "{controller}/{file}",
defaults: new { controller = "OrderForm", action = "Index", file = "" }
);
//here no need to have 40 routing table one is enough
//your controller/action will be
public class OrderForm
{
public ActionResult Index(string file)
{
ViewBag.Orderform=file
return View(file);
}
}
//view bag variable is accessible in view as well as in javascript
But I would say as best practice, you can modify default routing to access all urls and navigate it to same controller/action and let that action to return the view. After that use angular / knockout js to handle client side routing and based on it the partial views should be loaded.(still your url will be different for your 40 pages but noo need to pass it as query string)
//your route table will be
routes.MapRoute(
name: "default",
url: "{controller}/{file}",
defaults: new { controller = "OrderForm", action = "Index"}
);
//your controller will be
public class OrderForm
{
public ActionResult Index()
{
return View(file);
}
Navigation should be handled by client side routing
I have a view which lists some data. I want to make it sortable. The problem is that with my route configured
routes.MapRoute(
name: "Sort",
url: "Cars/Index/SortBy/{column}",
defaults: new { controller = "Cars", action = "Index", column = UrlParameter.Optional }
);
I am always getting null parameter in my controller class. I try opening /Cars/SortBy/columnname or /Cars/Index/SortBy/columnname it doesn't work. Only /Cars/Index?sortBy=columnname works
public ActionResult Index(string SortBy)
{
switch (SortBy) // SortBy is null
{
case "manufactuer":
return View(db.Cars.OrderBy(c => c.Model.Manufacturer.Name));
break;
case "model":
return View(db.Cars.OrderBy(c => c.Model.Name));
}
return View(db.Cars);
}
How to make it work?
You should change your action method parameter name to column as that is what you used in defining the route.
public ActionResult Index(string column)
{
return View();
}
Then it will work for the url Cars/Index/SortBy/model
If you want it to work for the url Cars/SortBy/model (without the Index), You can use this route definition.
routes.MapRoute(
name: "Sort",
url: "Cars/SortBy/{column}",
defaults: new { controller = "Cars", action = "Index", column = UrlParameter.Optional }
);
// Your other default route definition goes below this
Or if you are using Attribute routing,
[Route("Cars/SortBy/{column}")]
public ActionResult Index(string column)
{
return View();
}
Make sure to enable attribute routing in your RegisterRoutes method for attribute routing to work.
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapMvcAttributeRoutes();
//Custom and default route definitions goes here
}
I need my page names to have a dash in the name. E.G our-vision
I'm new to MVC & c# so I may be going about all this wrong.
Here is my controller:
public class HomeController : Controller
{
//
// GET: /Home/
public ActionResult Index()
{
return View();
}
//
// GET: /our-vision/
public ActionResult ourVision()
{
return View();
}
}
And then in my views, I have Views/Home/ourVision.cshtml.
When I compile and go to http://localhost/ourVision it works, but when I go to http://localhost/our-vision it does not.
Here is my routing:
routes.MapRoute(
"Default", // Route name
"{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
You'll need to do a few things in order to achieve that.
First, to achieve our-Vision, you'll need to give your action method the ActionName attribute, like so:
[ActionName("our-Vision")]
public ActionResult ourVision()
Next, you'll have to rename your ourVision.cshtml view to be our-Vision.cshtml
Finally, whenever you're using Url.Action or ActionLink, you need to use our-Vision and not vision, like so:
Url.Action("our-Vision", "Home");
IMHO
The best way to do this - is define new route in route engine:
routes.MapRoute(
"OurVision", // Route name
"our-vision", // URL with parameters
new { controller = "Home", action = "ourVision" } // Parameter defaults
);
I have a SiteController class in my MVC4 project,the 'Site' url is working fine, but I need a dynamic url part right after 'Site', I need the url to look like this:
mysite.com/Site/{DYNAMICSTRING}/Users(or whatever)
{DYNAMICSTRING} can be the name of a subsite, so the controller should check if that subsite does actually exist in the database.
Right now I'm using Query strings, but that is not what my client wants.
How can I do that?
Additional details
My routing:
routes.MapRoute(
"Subdomain", // Route name
"{controller}/{action}/{dynamicString}", // URL with parameters
new { controller = "Site", action = "Subdomain" } // Parameter defaults
);
My controller:
public ActionResult Subdomain(string dynamicString)
{
return View();
}
the value of dynamicString is null when I navigate to: /Site/Subdomain/SomeString
You have to configure routing. For example if you have Homecontroller:
public class HomeController:Controller
{
public ActionResult Subdomain(string dynamicString)
{
return View();
}
}
then you have to configure your routing something like that
routes.MapRoute(
"Subdomain", // Route name
"{controller}/{action}/{dynamicString}/anyOtherParams", // URL with parameters
new { controller = "Home", action = "Subdomain", dynamicString = "" } // Parameter defaults
);
You can do it like this:
routes.MapRoute(
name: "Default", // Route name
url:"Site/{dynamicstring}", // URL with parameters
defaults: new {controller = "Site", action = "Index" } // Defaults
);
you can keep adding parts to the url part like so
url:"Site/{dynamicstring}/{anythingelse}" // url:"Site/{dynamicstring}/{anythingelse}/{bla}/Test/{hello}/etc..."
or you can also have a catch all route like this:"
routes.MapRoute(
name: "Default", // Route name
url:"{*all}", // catch all
defaults: new {controller = "Site", action = "Index" } // Defaults
);
and fetch all other parts in your controllers index action, by splitting them on /
Make sure you put the custom route before your default otherwise the default route will pick it up.
in your controller you get something like this:
public ActionResult Index(string dynamicstring, string anythingelse)
{
return View();
}
and if you then pass in a url like this:
http://www.mysite.com/Site/test.nl/jordy
your dynamicstring will have the value "test.nl" and your anythingelse will have "jordy"
I hope this helps