I'm trying to create a route to a specific controller/action which needs to accept optional querystring parameters.
the urls i'd like to accept are:
/Products/ProductsListJson
/Products/ProductsListJson?productTypeId=1
/Products/ProductsListJson?productTypeId=1&brandId=2
/Products/ProductsListJson?productTypeId=1&brandId=2&year=2010
I have an action like this:
public JsonResult ProductsListJson(int productTypeId, int brandId, int year)
And a route like this:
routes.MapRoute(
null, "Products/ProductsListJson",
new { controller = "Products", action = "ProductsListJson", productTypeId = 0, brandId = 0, year = 0 }
);
I assumed that the action "ProductsListJson" would simply see the querystring urls and map them to the appropriate arguments however this is not happening.
Anyone know how this could be achived?
You don't need to specify their values in the route if those parameters are passed in the query string:
routes.MapRoute(
null, "Products/ProductsListJson",
new { controller = "Products", action = "ProductsListJson" }
);
and your action:
public ActionResult ProductsListJson(int? productTypeId, int? brandId, int? year)
{
...
}
but you probably don't need a specific route for this as the default route will handle it just fine:
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
Related
I am trying to setup a BaseController to handle culture as part of the url (based on ASP.NET MVC 5 Internationalization). My implementation works properly as long as I disable my Areas' registration.
When One of my Area is registered, if I try to input a wrong/not supported culture (http://localhost:52639/zz/), I experience a 404 error with a request URL: http://localhost:52639/fr/Test/Post.
I have checked my routes are properly registered.
If I do the same while disabling the Areas registration, the base controller and routing behave correctly if I type the following URL: http://localhost:52639/zz/ I am redirected to http://localhost:52639/fr/ (default culture).
Those are my routes:
public static void RegisterRoutes(RouteCollection routes)
{
var namespaces = new[]{typeof(PostController).Namespace};
routes.IgnoreRoute("favicon.ico");
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute("PostToHack", "{culture}/Post/{idAndSlug}", new { culture = "", Controller = "Post", Action = "Show" }, namespaces);
routes.MapRoute("Post", "{culture}/Post/{id}-{slug}", new { culture = "", Controller = "Post", Action = "Show" }, namespaces);
routes.MapRoute("TagToHack", "{culture}/Tag/{idAndSlug}", new { culture = "", Controller = "Post", Action = "Tag" }, namespaces);
routes.MapRoute("Tag", "{culture}/Tag/{id}-{slug}", new { culture = "", Controller = "Post", Action = "Tag" }, namespaces);
routes.MapRoute("Logout", "{culture}/Logout", new { culture = "", Controller = "Authentication", Action = "Logout" }, namespaces);
routes.MapRoute("Login", "{culture}/Login", new { culture = "", Controller = "Authentication", Action = "Login" }, namespaces);
//Error routes
routes.MapRoute("Error404", "{culture}/errors/404", new { culture = "", Controller = "Errors", Action = "NotFound" }, namespaces);
routes.MapRoute("Error500", "{culture}/errors/500", new { culture = "", Controller = "Errors", Action = "Error" }, namespaces);
routes.MapRoute("Home", "{culture}", new { culture = "", Controller = "Post", Action = "Index"},namespaces);
//Never to be called by user which is why it comes after MapRoute Home so it is always overwritten by it
routes.MapRoute("Sidebar", "{culture}", new { culture = "", Controller = "Layout", Action = "Sidebar"},namespaces);//This is a "child-only" controller
routes.MapRoute("NavigationBar", "{culture}", new { culture = "", Controller = "Layout", Action = "NavigationBar"},namespaces);//This is a "child-only" controller
Area Route
public override void RegisterArea(AreaRegistrationContext context)
{
var namespaces = new[] { typeof(PostsController).Namespace };
context.MapRoute(
"admin_default",
"{culture}/admin/{controller}/{action}/{id}",
new { culture = "", action = "Index", id = UrlParameter.Optional }, namespaces
);
}
Base Controller:
public class BaseController : Controller
{
protected override IAsyncResult BeginExecuteCore(AsyncCallback callback, object state)
{
var cultureName = RouteData.Values["culture"] as string;
// Attempt to read the culture cookie from Request
if (cultureName == null)
cultureName = (Request.UserLanguages != null) && (Request.UserLanguages.Length > 0)
? Request.UserLanguages[0]
: null; // obtain it from HTTP header AcceptLanguages
// Validate culture name
cultureName = CultureHelper.GetImplementedCulture(cultureName); // This is safe
if (RouteData.Values["culture"] as string != cultureName)
{
// Force a valid culture in the URL
RouteData.Values["culture"] = cultureName.ToLowerInvariant(); // lower case too
// Redirect user
Response.RedirectToRoute(RouteData.Values);
}
// Modify current thread's cultures
Thread.CurrentThread.CurrentCulture = new CultureInfo(cultureName);
Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture;
return base.BeginExecuteCore(callback, state);
}
}
After some more digging I have found a solution that work for me. My issue was coming from the order in which I was registering my routes. I was registering my Area's routes first:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RouteConfig.RegisterRoutes(RouteTable.Routes);
}
I inverted the order and made sure that I was only registering my Area's routes after:
protected void Application_Start()
{
RouteConfig.RegisterRoutes(RouteTable.Routes);
AreaRegistration.RegisterAllAreas();
}
Currently this works:
/api/Company/1089?children=branches
Controller:
public IEnumerable<Branch> Get(int id, string children)
I want my url to be this:
/api/Company/1089/branches
I can't figure out how to configure the route.
This doesn't work:
routes.MapRoute(
name: "cb",
url: "{controller}/{action}/{id}/{children}",
defaults: new { controller = "Company", action = "Get",
id = UrlParameter.Optional, children = UrlParameter.Optional }
);
api/{controller}/{id}/{children}
here is how I have routing setup.
routes.MapHttpRoute(
name: "Authors",
routeTemplate: "api/authors",
defaults: new { controller = "authors" }
);
controller action method
// GET /api/authors/
public string GetAuthors(string author_ids)
{
return data;
}
Url http://site.com/api/authors?author_ids=1 actually calls controller action but when I don't pass querystring parameter, it says no controller action matching found.
How to handle optional querystring parameter when defining route?
// GET /api/authors/
public IEnumerable<string> GetAuthors()
{
return data;
}
You will need to define an action that takes no parameters.
It would be better, however, to add id to your route as optional:
routes.MapHttpRoute(
name: "Authors",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
You can be specific like:
routes.MapHttpRoute(
name: "Authors",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
and Action can be:
// GET /api/authors/?XXXX
public IEnumerable<string> GetAuthors( [FromUri] String author_ids)
{
return data;
}
This will only match query string . [FromUri] lets the parameter to be taken from query string.
You may specific like:
routes.MapHttpRoute(
name: "Authors",
routeTemplate: "api/{controller}/{author_ids}",
defaults: new { author_ids = RouteParameter.Optional }
);
I've defined the following route:
routes.MapRoute(
null,
"foo/{id}/{title}",
new { controller = "Boo", action = "Details" }
);
When I call this method:
Url.Action("Details", "Boo", new { id = article.Id, title = article.Title })
I get the following URL:
http://localhost:57553/foo/1/Some%20text%20Š
I would like to create a new route that will lowercase all characters and replace some of them.
e.g.
http://localhost:57553/foo/1/some-text-s
Rules:
Uppercase -> lowercase
' ' -> '-'
'Š' -> 's'
etc.
Any help would be greatly appreciated!
Seems like a perfect candidate for a custom route:
public class MyRoute : Route
{
public MyRoute(string url, object defaultValues)
: base(url, new RouteValueDictionary(defaultValues), new MvcRouteHandler())
{
}
public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
{
values = new RouteValueDictionary(values);
var title = values["title"] as string;
if (!string.IsNullOrEmpty(title))
{
values["title"] = SEOify(title);
}
return base.GetVirtualPath(requestContext, values);
}
private string SEOify(string title)
{
throw new NotImplementedException();
}
}
which will be registered like this:
routes.Add(
"myRoute",
new MyRoute(
"foo/{id}/{title}",
new { controller = "Boo", action = "Details" }
)
);
Now all you have to do is to implement your SEO requirements in the SEOify function that I left. By the way you could get some inspiration from the way StackOverflow does it for the question titles.
Currently I have a Controller named StoreController. There are three Categories : books, movies, and games. How can i make sure that the url's
http://mywebsite.com/store/books,
http://mywebsite.com/store/movies
http://mywebsite.com/store/games
match a single action method. Right now, I am having three separate action methods books(); movies(); games(); doing the same thing, i.e listing the products in them
Did you try like this?
routes.MapRoute(
"Default", // Route name
"{controller}/{id}", // URL with parameters
new { controller = "Store", action = "Index", id = UrlParameter.Optional } // Parameter defaults
, null }
)
and you make Controller like
public ActionResult Index(string id)
{
if(id == "books"){
}
else if(id == "movies"){
}
else{// this is null case
}
return Content("hello");// test
}