I have the following area routes setup.
context.MapRoute(
"Admin_default3",
"Admin/{controller}/{action}/{id}/{id2}/{id3}",
new { action = "Index" }
);
context.MapRoute(
"Admin_default2",
"Admin/{controller}/{action}/{id}/{id2}",
new { action = "Index"}
);
context.MapRoute(
"Admin_default",
"Admin/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional }
);
When a controller action is hit I do something like the following where I place the params into readable variable names.
public ActionResult Search(Guid? id, int? id2, bool? id3)
{
Guid? source = id;
int daysOld = id2;
bool includeNonEnglish = id3;
//.... Action!
}
Should I continue that way? Should I create a plethora of routes?
thank you
I would create more routes. That way, you have things like:
Html.ActionLink(title, "Action", "Controller", new { source = <value>, daysOld = <value>, includeNonEnglish = <value> });
Instead of:
Html.ActionLink(title, "Action", "Controller", new { id = <value>, id2 = <value>, id3 = <value> });
Among other things (like AJAX calls with jQuery, where you use Json for specifying parameters). It would make things more readable. It would also help if you're using, or going to use, T4MVC.
Related
I have a route that is defined like this:
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional, area = "" }, // Parameter defaults
new { home = new HomePageConstraint() }
);
public class HomePageConstraint : IRouteConstraint
{
public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
{
return !httpContext.Request.RawUrl.StartsWith("/home", StringComparison.InvariantCultureIgnoreCase);
}
}
And I am trying to test it like this:
[Test]
public void Home_Load_Homepage()
{
"~/".ShouldMapTo<HomeController>(x => x.Index());
}
The problem I have is that the httpContext is null, so the test fails. how can I inject http context into a constraint?
In the end I did this:
var context = new FakeHttpContext("~/");
var fakeRequest = new FakeRequest("~/", new Uri("http://localhost/"), new Uri("http://localhost/"));
context.SetRequest(fakeRequest);
var route = RouteTable.Routes.GetRouteData(context);
route.ShouldMapTo<HomeController>(x => x.Index());
i have an area and change my route to this
public class WeblogsAreaRegistration : AreaRegistration
{
public override string AreaName
{
get
{
return "Weblogs";
}
}
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Weblogs_default",
"Weblogs/{controller}/{action}/{blogName}/{post}",
new { action = "Index",
blogName = UrlParameter.Optional,post=UrlParameter.Optional}
);
}
}
and it is my index
public ActionResult Index(string blogName,int post)
{
return View();
}
it works fine by this:
http://localhost:2927/Weblogs/Blogs?blogName=Myco&Post=3
but works not by
http://localhost:2927/Weblogs/Blogs?blogName=Myco
what is the problem?
how can i change my rout to works with this URL:
http://localhost:2927/Weblogs/Blogs/Myco/3
"myco" is blog name and 3 is post number.
is it possible?
Remove your action and controller tokens from your route. Modify it to be like so:
context.MapRoute(
"Weblogs_default",
"Weblogs/Blogs/{blogName}/{post}",
new { action = "Index",
Controller = "Blogs",
blogName = UrlParameter.Optional,
post=UrlParameter.Optional}
);
Here is my desired url format: /product-24-hid-35wh4-cx-dsgtx
How can I map this URL to my action method:
public ActionResult Product(int id)
Here is my routing code:
routes.MapRoute(
"ProductDetail",
"product-{id}-{name}",
new { controller = "product", action = "detail", name = UrlParameter.Optional },
new string[] { "SphereLight.Controllers" }
);
However, it does not work; I used phil haack's routedebugger to test this route, and below is the result:
Key Value
name dsgtx
id 24-hid-35wh4-cx
controller product
action detail
Only id = 24 is correct.
In one word, I need a route to match:
/product-24
/product-24-
/product-24-hid-35wh4-cx-dsgtx
Try to add constraints in your MapRoute:
routes.MapRoute(
"ProductDetail",
"product-{id}-{name}",
new { controller = "product", action = "detail", name = UrlParameter.Optional },
new { id = #"\d+" }, // <-- change it for #"[^-]+", if it can be non-digit
new string[] { "SphereLight.Controllers" }
);
UPDATE:
Finally got it.
The main problem is that you can't use parameters which contains the same separator.
For example, the example above will work with /product-24-nm, but not with product-24-nm-smth.
So, let's try this solution:
I've made it on the default routing, you can make it your way
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional },
new MyRouteHandler()
).RouteHandler = new MyRouteHandler();
Implementation of MyRouteHandler:
public class MyRouteHandler : MvcRouteHandler
{
private static readonly Regex ProductPattern = new Regex(#"product\-(\d+)\-?(.*)");
protected override IHttpHandler GetHttpHandler(RequestContext requestContext)
{
var match = ProductPattern.Match(requestContext.RouteData.Values["controller"].ToString());
if (match.Length > 0)
{
requestContext.RouteData.Values["controller"] = "Home";
requestContext.RouteData.Values["action"] = "Detail";
requestContext.RouteData.Values["id"] = match.Groups[1].Value;
requestContext.RouteData.Values["name"] = match.Groups[2].Value;
}
return base.GetHttpHandler(requestContext);
}
}
So, the main idea is to check if the values matches our pattern product-id-name in the handler, and not trying to make it in MapRoute.
Hope this helps.
I am start to learn the MVC3, But i have some problem on WebGrid,
The Controller name is TestController, so i navigate to :
http://localhost:53503/Test/
And the Webgrid shown as below:
two column : ID and Name.
the 3rd & 4th column : Actionlink and item.GetSelectLink.
The first problem is :
Assume i viewing page 3 of webgrid, and press the ActionLink,after go-thought the TestContoller's Action, the webgrid will return to page 1 after PostBack.
However,if i press the [View(GetSelectLink)] on right end:
(e.g. http://localhost:53503/Test/?gridItems_page=3&gridItems_selectedRow=3
It works.
So, i should use ActionLink or GetSelectLink for general Add/Update/Delete operation?
MVC3 hasn't viewstate / control state, so how can i preserve the current page selection after PostBack?
The second problem is :
The (href) of ActionLink is :
http://localhost:53503/Test/GetSelection/7?Name=PSP
I would make it to
http://localhost:53503/Test/GetSelection/7/PSP
I add a new route to global.asax, but it is no luck.
Thanks you very much for help.
It is my code:
Views/Test/Index.cshtml
#model List<MvcContract.Controllers.Products>
#{
System.Web.Helpers.WebGrid grid = new System.Web.Helpers.WebGrid(
source: Model,
canPage: true,
rowsPerPage: 3,
fieldNamePrefix: "gridItems_",
pageFieldName: "page",
selectionFieldName: "selectedRow"
);
}
#{
if (Model != null)
{
#grid.GetHtml(
columns: grid.Columns(
grid.Column("ID"),
grid.Column("Name"),
grid.Column(format: (item) => Html.ActionLink("View(ActionLink)", "GetSelection", new { ID = item.ID, Name = item.Name })),
grid.Column(format: (item) => item.GetSelectLink("View(GetSelectLink)"))
)
);
}
}
Controllers/TestController.cs
namespace MvcContract.Controllers
{
public class Products
{
public string ID { get; set; }
public string Name { get; set; }
public List<Products> GetItems()
{
List<Products> items = new List<Products>();
items.Add(new Products() { ID = "1", Name = "PS3" });
items.Add(new Products() { ID = "2", Name = "XBox360" });
items.Add(new Products() { ID = "3", Name = "Wii" });
items.Add(new Products() { ID = "4", Name = "Saturn" });
items.Add(new Products() { ID = "5", Name = "Dreamcast" });
items.Add(new Products() { ID = "6", Name = "NDS" });
items.Add(new Products() { ID = "7", Name = "PSP" });
items.Add(new Products() { ID = "8", Name = "NeoGeo" });
items.Add(new Products() { ID = "9", Name = "3DO" });
items.Add(new Products() { ID = "10", Name = "Playdia" });
return items;
}
}
public class TestController : Controller
{
//Bind data to WebGrid
public ActionResult Index()
{
Products products = new Products();
return View(products.GetItems());
}
//Some Logic
public ActionResult GetSelection(string ID, string Name)
{
string SelectedID = ID;
return RedirectToAction("Index");
}
}
}
RegisterRoutes() in Global.asax.cs
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(
"Test_GetSelection", // Route name
"{controller}/{action}/{id}/{name}", // URL with parameters
new { controller = "Test", action = "GetSelection", id = UrlParameter.Optional, name = UrlParameter.Optional } // Parameter defaults
);
}
Check out this discussion. I think one of several solutions there may solve your issue.
Since its been a whole year since you posted this, please post an answer if you figured it out another way.
I have this route map (notice that topicName is ignored):
routes.MapRoute(
"Topics", // Route name
"Topic/{topicName}/{action}",
new { controller = "Topic", action = "AddQuestion" });
And I want it to defaultly map to this Url:
http://localhost:51421/Topic/SomeName/AddQuestion?topicId=1 (or if that's not possible,to this url: http://localhost:51421/Topic/SomeName/AddQuestion/topicId/1)
(which should invoke this action:
public ActionResult AddQuestion(int topicId)
{
return View();
}
)
But either way I need all this data in the url.
What's the correct way to do that?
You could add a default route:
routes.MapRoute(
"Topics",
"Topic/{topicName}/{action}/{topicId}",
new { controller = "Topic", action = "AddQuestion", topicId = "1" }
);
routes.MapRoute(
"Default",
"{controller}/{action}/{topicId}",
new { controller = "Topic", action = "AddQuestion", topicId = "1" }
);