Routing to controller with a required, non-empty Guid parameter - asp.net-mvc

I would like to map http://localhost/Guid-goes-here to ResellerController and fire Index action of that controller only when Guid-goes-here is not the empty Guid.
My routing table looks like this:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Reseller",
"{id}",
new { controller = "Reseller", action = "Index", id = Guid.Empty }
// We can mark parameters as UrlParameter.Optional, but how to make it required?
);
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
}
The action on the ResellerController looks like this:
public ActionResult Index(Guid id)
{
// do some stuff with non-empty guid here
}
Once the application has started, navigating to http://localhost routes me to the ResellerController with the empty Guid as the argument to the Index action's id parameter.

public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Reseller",
"{id}",
new { controller = "Reseller", action = "Index", id = UrlParameter.Optional },
new { id = #"^(\{{0,1}([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}\}{0,1})$" }
);
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
}
or if you want a more robust constraint than some cryptic regex:
public class GuidConstraint : IRouteConstraint
{
public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
{
var value = values[parameterName] as string;
Guid guid;
if (!string.IsNullOrEmpty(value) && Guid.TryParse(value, out guid))
{
return true;
}
return false;
}
}
and then:
routes.MapRoute(
"Reseller",
"{id}",
new { controller = "Reseller", action = "Index", id = UrlParameter.Optional },
new { id = new GuidConstraint() }
);

You need to include a constraint in the routing definition. Have a look on this post: http://blogs.microsoft.co.il/blogs/bursteg/archive/2009/01/11/asp-net-mvc-route-constraints.aspx

Related

How to display only name in url instead of id in mvc.net using routing

I am getting url like http://localhost:49671/TestRoutes/Display?f=hi&i=2
I want it like http://localhost:49671/TestRoutes/Display/hi
I call it from Index method.
[HttpPost]
public ActionResult Index(int? e )
{
// return View("Display", new { f = "hi", i = 2 });
return RedirectToAction("Display", new { f = "hi", i = 2 });
}
Index view
#model Try.Models.TestRoutes
#using (Html.BeginForm())
{
Model.e = 5 ;
<input type="submit" value="Create" class="btn btn-default" />
}
Display Action method
// [Route("TestRoutes/{s}")]
public ActionResult Display(string s, int i)
{
return View();
}
Route config file
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Professional", // Route name
"{controller}/{action}/{id}/{name}", // URL with parameters
new { controller = "TestRoutes", action = "Display", s = UrlParameter.Optional, i = UrlParameter.Optional
});
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional
});
You need to change your route definition to
routes.MapRoute(
name: "Professional",
url: "TestRoutes/Display/{s}/{i}",
default: new { controller = "TestRoutes", action = "Display", i = UrlParameter.Optional }
);
so that the names of the placeholders match the names of the parameters in your method. Note also that only the last parameter can be marked as UrlParameter.Optional (otherwise the RoutingEngine cannot match up the segments and the values will be added as query string parameters, not route values)
Then you need to change the controller method to match the route/method parameters
[HttpPost]
public ActionResult Index(int? e )
{
return RedirectToAction("Display", new { s = "hi", i = 2 }); // s not f
}
change your route as
routes.MapRoute(
"Professional", // Route name
"{controller}/{action}/{name}", // URL with parameters
new
{
controller = "TestRoutes",
action = "Display"
} // Parameter defaults
);
and your action as
public ActionResult Display(string name)
{
//action goes here
}
Remove the maproute code:
routes.MapRoute(
"Professional", // Route name
"{controller}/{action}/{id}/{name}", // URL with parameters
new { controller = "TestRoutes", action = "Display", s = UrlParameter.Optional, i = UrlParameter.Optional
});
Use attribute routing code:
[Route("TestRoutes/{s}/{i?}")]
public ActionResult Display(string s, int? i)
{
return View();
}
You can also try using Attribute Routing. You can control your routes easier with attribute routing.
Firstly change your RouteConfig.cs like that:
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapMvcAttributeRoutes();
//routes.MapRoute(
// name: "Default",
// url: "{controller}/{action}/{id}",
// defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
//);
}
}
After that change your controller files like that:
namespace YourProjectName.Controllers
{
[RoutePrefix("Home")]
[Route("{action}/{id=0}")]
public class HomeController : Controller
{
[Route("Index")]
public ActionResult Index()
{
return View();
}
[Route("ChangeAddress/{addressID}")]
public ActionResult ChangeAddress(int addressID)
{
//your codes to change address
}
}
You can also learn more about Attribute Routing in this post:
https://blogs.msdn.microsoft.com/webdev/2013/10/17/attribute-routing-in-asp-net-mvc-5/
Another way to solve this problem is to put the proper route before the default route, as follows:
routes.MapRoute(name: "MyRouteName", url: "Id", defaults: new { controller= "Home", action = "Index",id= Id });
Default route:
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{Id}",
defaults: new { controller = "Home", action = "Index",id= Id }
);

UrlParameter.Optional not working in Razor

I am using below code in layout for links:
But it's not working, here is my route Config
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home" , action = "Index", id = UrlParameter.Optional }
);
}
This is my NewProduct Controller:
public ActionResult NewProduct(int id = -1)
{
NewProductModel m = new NewProductModel();
return View(m);
}
What is problem in my UrlParameter.optional
When you using #Url.Action helper you should pass the actual value to parameter like this:
#Url.Action("NewProduct", "Administrator", new { id = 1 })
UrlParameter.Optional should be used only in RouteConfig as you see in your code.
in NewProduct controller :
public ActionResult NewProduct(int id = -1)
{
NewProductModel m = new NewProductModel();
m.Id = id;
return View(m);
}
and for Link

MVC Route static value

I'm not sure if this is possible using mvc routing, I haven't been able to find a similar example.
I have about 5~ controller actions that are the same method, so I'd like to refactor them into a single action. I'd like to pass an enum value to the controller to tell it what path it should pass to lower layers.
Example:
public ActionResult ViewPage(int id, PageEnum page) {
var model = MyService.GetModelForTemplate(id, page);
return ("ViewPage", model);
}
Then the user could access this either through /PagesTypeOne/ViewPage/, or /PagesTypeTwo/ViewPage/. Both routes leading to the same endpoint.
Route table attempt:
routes.MapRoute(
name: "typeOne",
url: "PagesTypeOne/{action}/{id}",
defaults: new { controller = "Pages", action = "ViewPage", id = UrlParameter.Optional, page = PageEnum.TypeOne, }
);
routes.MapRoute(
name: "typeTwo",
url: "PagesTypeTwo/{action}/{id}",
defaults: new { controller = "Pages", action = "ViewPage", id = UrlParameter.Optional, page = PageEnum.TypeTwo, }
);
This obviously isn't working.
Is there a way I can do something like this? It would make my code much more concise.
screen != page, so if the property on the anonymous type matches the parameter it will work:
public ActionResult ViewPage(int id, PageEnum screen) {
var model = MyService.GetModelForTemplate(screen);
return ("ViewPage", model);
}
Updated: Created a empty application and it work flawlessly:
namespace MvcApplication6
{
public class MvcApplication : System.Web.HttpApplication
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
}
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Test1",
"PagesTypeOne/{action}/{id}", // URL with parameters
new { controller = "Home",
action = "Index",
id = UrlParameter.Optional,
page = PageEnum.PageOne } // Parameter defaults
);
routes.MapRoute(
"Test2",
"PagesTypeTwo/{action}/{id}", // URL with parameters
new { controller = "Home",
action = "Index",
id = UrlParameter.Optional,
page = PageEnum.PageOne } // Parameter defaults
);
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home",
action = "Index",
id = UrlParameter.Optional } // Parameter defaults
);
}
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
}
}
}
public enum PageEnum
{
Undefined,
PageOne,
PageTwo
}
Controller:
namespace MvcApplication6.Controllers
{
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
public ActionResult ViewPage(int id, PageEnum page)
{
var debug = 1; // break point
return new EmptyResult();
}
}
}
you can make it completely dynamic with one route definition:
// the route must be defined as the first route
routes.MapRoute(
name: "typeTwo",
url: "{page}/ViewPage/{id}",
defaults: new { controller = "Pages", action = "ViewPage", id = UrlParameter.Optional },
new { page= getPageTypes() }
);
the getPageTypes method:
private static string getPageTypes()
{
var pageTypes = Enum.GetNames(typeof(PageEnum));
return string.Join("|", pageTypes );
}
but PagesTypeOne/ViewPage/4 part must match the enum's name.

asp mvc 5 Attribute routing not firing

I'm trying to use the attribute routing in a new project, but I can't get it to work.
Here is what I have so far :
[RoutePrefix("Product")]
public class ProductController : Controller
{
[Route("{id}/{title}", Name = "Product Details")]
public ActionResult Index(int id = 0, string title = "")
{
Product p = Product.Get(id);
return View(p);
}
}
And here is my RouteConfig.cs :
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
//routes.MapRoute(
// "Product Details",
// "Product/{id}/{title}",
// new { controller = "Product", action = "Index", id = UrlParameter.Optional, title = UrlParameter.Optional }
//);
routes.MapRoute(
name: "DefaultIndex",
url: "{controller}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
If I remove the Routing attributes and uncomment the first route in my RouteConfig.cs it works fine, but I'd like to stick with route attributes.
Any idea why it's not working correctly ?
The URL I want to use is : http://www.mydomain.com/Product/12345/ProductName
EDIT, here is my Application_Start()
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleMobileConfig.RegisterBundles(BundleTable.Bundles);
}
Looks like its treating the {id} as an action.
Try this:
[Route("{id:int}/{title}", Name = "Product Details")]
Or this
[Route("Product/{id}/{title}", Name = "Product Details")]

Different default routes for different roles

Is it possible to create a different default route for a different user role?
e.g.
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
routes.MapRoute(
"Admin", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "totalrewardstatement", action = "Details", id = UrlParameter.Optional } // Parameter defaults
);
}
Have the default route above for normal users but use the admin one if an admin user logs in?
Role based routing is not supported in MVC. What you do is have default controller which checks for the roles and redirect to that controller
public ActionResult Index()
{
if (User.IsInRole("Supervisor"))
{
return RedirectToAction("Index", "InvitationS");
}
return View();
}
http://forums.asp.net/t/1994888.aspx?role+based+routing+asp+net+mvc
Using a custom RouteConstraint did the trick for me on mvc 5.
public class RoleConstraint : IRouteConstraint
{
public bool Match
(
HttpContextBase httpContext,
Route route,
string parameterName,
RouteValueDictionary values,
RouteDirection routeDirection
)
{
return httpContext.User.IsInRole(parameterName) ;
}
}
RouteConfig.cs
routes.MapRoute(
name: "Reader_Home",
url: "",
defaults: new { controller = "Reader", action = "Index", id = UrlParameter.Optional },
constraints: new { reader_role = new RoleConstraint() }
);
routes.MapRoute(
name: "Author_Home",
url: "",
defaults: new { controller = "Publication", action = "Index", id = UrlParameter.Optional },
constraints: new { author_role = new RoleConstraint() }
);
I'm using the parameterName (author_role and reader_role) as the role name to check for simplification.

Resources