URL rewriting in MVC3 - asp.net-mvc-3

I am working on a project for a local college using MVC3. I have came across a requirement at which I am stuck and can't find any wayout.
Let suppose my URL is www.abc.com
The requirement is that if we type teacher name after the URL we get the detailed view of the teacher, like:
www.abc.com/john
www.abc.com/smith
I asked for option like www.abc.com/teacher=john but it has been rejected.
Is this something relevant to URL rewriting or some other wayout, as there can be many teachers in database so I can't make methods in controllers for every teacher.
Can anyone please guide me for this scenario?
Kind Regards

MVC does this natively.
Just create a route for it:
routes.MapRoute(
"Teacher route",
"/{teacher}",
new { controller = "SomeController", action = "SomeAction" }
)
Note that this will conflict with any other /Whatever URLs (eg, /About); to avoid that, you can use my MapDefaultController() extension to map a route for a specific controller before this one.

Related

MVC Routing Engine routes same formatted route to different controller actions

Okay, I did my homework and search SO, and indeed I found similar questions but not reporting the behavior I'm getting.
Here is the deal, I have defined a route:
routes.MapRoute("CategoryName", "Category/Name/{text}",
new { controller = "Category", action = "Name", text = "" });
The twist here is the following:
This url: http://www.url.com/Category/Name/existingCategoryName
And this url: http://www.url.com/Category/Name/anotherExistingCategoryName
Both url's should go to the same controller method which is public ActionResult Name(string text) but sadly the first url is going to the default Index method, the second is being routed correctly.
I wonder why this happens, as I've been with .net mvc for several years and never experienced this behavior.
As a side note here are some facts:
As it's being route to different methods, I doubt the code inside them has something to do with it.
When manually write the category to something it doesn't exists in the DB as a category name it goes through the Name method.
The routes are placed correctly, as I'm aware the first route that matches the pattern will win.
Even I tried place the CategoryName route first, the behavior is the same.
When writing each link in the Category/Index I use the same #Html.RouteLink() helper, so all the links are formatted the same way.
Thanks in advance!
Are you using the - sign in the failing route?
Maybe you can find more information with the Routing debugger
And maybe you can look at this question: Failing ASP.NET MVC route. Is this a bug or corner case?
Phil Haack also give an possible answer to your problem in: ASP.NET routing: Literal sub-segment between tokens, and route values with a character from the literal sub-segment

localized routes solution

I built a french/english app and I would like to use the same controller/view for both language but to have a different route that is map to the current language. Let say I have website.com/Account/Register that return to my Account controller and Register action, I would love to have a route that is website.com/Comptes/Inscription. I know that I can add a custom route in the RegisterRoute section like so :
routes.MapRoute(
"AccountFr", // Route name
"comptes/inscription", // URL with parameters
new { controller = "Account", action = "Register" } // Parameter defaults
);
But it will need a lot of [boring] code to write all the possibles routes and also, I think it won't work when I will use T4MVC as #Url.Action(MVC.Account.Register()) will return /Account/Register no mater if I'm in french or in english.
Anyone as suggestions/ideas for this problem?
Thanks!
EDIT
Since it does not seem to have a good solution using T4MVC does anyone have an other good solution?
Unfortunately, this won't easily work with T4MVC. The root of the problem is that when going through T4MVC, you can't pick a specific route. Instead, the route gets selected based on the Controller, action and parameters.

MVC3 how to create URLs

I see people using Html.ActionLink() and Url.RouteUrl() etc. etc.
But surely this will lead to a maintenance nightmare if routes need to be redesigned?
How are people organising the generation of URLs in a typesafe and manageable way?
Strongly typed URL generation via lambda expressions was available for a period of time during the MVC 1.0 beta timeframe. It was removed since the MVC architecture does not actually have a 1-to-1 mapping between action names and controller method names. See this Phil Haack blog post for details.
It is of course still possible to do it, and assuming you're not using action names that differ from method names, it should work fine.
You can use T4MVC to generate typesafe checks at compile time for your MVC urls.
T4MVC analyses your Controller classes, and generates code that will generate typesafe url's.
Instead of
#Html.ActionLink("New customer", "Create", new { Controller = "Customer", orgID = orgID })
You can use code like:
#Html.ActionLink("New customer", MVC.Customer.Create(orgID))
If you want to call a action you use the Html.ActionLink(). This will create a <a href="..." ></a> hyperlink to chosen action.
If you want to create a url and use it not for a hyperlink, you can use the Url.Content() or the Url.RouteUrl(). The content accepts a string and gerenates a safe url. The Route url takes a route object.

MVC3 Routing - Routes that builds on each other

I have an AREA setup in my project. I need to make the routes for the area progressive, meaning that the route will build on each other.
I'm looking at this as something like a link list. Each node in the list will have a reference to a parent. As move from left to right in the list it builds, and from right to left it removes.
In the area, I have companies and that have contacts, and child companies.
For example, I have companies that would have the following:
/Companies/list
/Company/{Id}
/Company/{id}/add
/Company/{id}/edit
/Company/{id}/delete
For the contact section I need to create the following routes:
/Company/{id}/contacts/list
/Company/{id}/contact/{id}/add
/Company/{id}/contact/{id}/edit
/Company/{id}/contact/{id}/delete
How do I make sure that /Company/{id} is always in the Contact and Child Company sections of the route?
I hope that I have made my question clear.
Subjective Generalities (take with a pinch of salt):
First off, you are using Company (singular) for companies, but then you are using contacts (plural) for the contacts. There is nothing wrong with this, from a structural point of view, but your users will thank you if you are consistent with your pluralizations. I would use the plural in both cases, but that is just my preference... it looks more like English.
You also use lower case for contacts, but upper case for Company. Doesn't look professional.
The next thing that is confusing is that you are using two {id} parameters, one for companies, one for contacts. I presume these are the ids for Company and Contacts respectively. But I am confused, but being human, I am able to deduce context unlike a computer. So you would be better of specifying the parameters in your routes. Ie:
/Companies/{CompanyId}/Contacts/{ContactId}/[action]
Answering your Question with an Example:
I get the feel you don't understand routes properly. If you did, your question would be more specific.
Your route parameters can come from a number of sources, depending on how the route is requested.
You could hard code it into a link. Or, more usefully, your route registration would be designed to catch requests that map to your Action signatures.
For example, I have an eLearning app with tutors, pupils, courses and steps (ie, the steps are like sections of a course, the pupil advances through the course step by step)
The route registration looks something like:
Route or Area Registration:
context.MapRoute(
"StepDisplay",
"Course/{CourseId}/Step/{StepOrder}/Pupil/{PupilName}/{TutorName}",
new { controller = "Course", action = "Display", TutorName = UrlParameter.Optional },
new[] { "ES.eLearningFE.Areas.Courses.Controllers" }
);
This route will catch a request from the following ActionLink:
ActionLink in View:
#Html.ActionLink(#StepTitle, MVC.Courses.Course.Actions.Display(Model.CourseId, step.StepOrder, Model.Pupil.UserName, tutorName))
Now, I just need to show you the Display action's signature:
CoursesController:
public virtual ActionResult Display(int CourseId, int StepOrder, string PupilName, string TutorName)
There are a few things to note here:
That I am able to call this specific route by giving the user a link to click on.
I construct this link using the Html.ActionLink helper
I have used David Ebbo's t4mvc nuget package so that I can specify the action I am calling and its parameters. By which I mean specifying the ActionResult parameter of the Html.ActionLink helper using:
MVC.Courses.Course.Actions.Display(Model.CourseId, step.StepOrder, Model.Pupil.UserName, tutorName)
If you think about it, what routes do is translate the url of a request into an action, so the parameters of my route are either the controller name, the action name or else they are the names of parameters in the action signature.
You can see now why naming two distinct route parameters with the same
name is such a bad idea (largely because it won't work).
So, look at your action signatures, and design your routes and your action links so that the everything marries up together.
MVC doesn't work by magic!! (Although the way it uses name conventions might lead you to believe it)

need help with mvc & routes

I'm very new to MVC and I'm trying to get a new site set up using it. For SEO reasons we need to make the url of a page something like "Recruiter/4359/John_Smith" or basically {controller}/{id}/{name}. I have that working when I create the url in the code behind like so...
//r is a recruiter object that is part of the results for the view
r.Summary = searchResult.Summary + "... <a href=\"/Recruiter/" + r.Id + "/" + r.FirstName + "_" + r.LastName + "\">Read More</a>"
But when I am using the collection of results from a search in my view and iterating through them I am trying to create another link to the same page doing something like <%=Html.ActionLink<RecruiterController>(x => x.Detail((int)r.Id), r.RecruiterName)%> but that doesn't work. When I use that code in the view it gives me a url in the form of /Recruiter/Detail/4359 I was told by a coworker that I should use the Html.ActionLink to create the link in both the view and the controller so that if the route changes in the future it will automatically work. Unfortunately he wasn't sure how to do that in this case. So, my problems are...
How can I make the Html.ActionLink work in the view to create a url like I need (like r.Summary above)?
How do I use the Html.ActionLink in a controller instead of hardcoding the link like I have above?
I came across this blog post which got me going in the right direction.
http://www.chadmoran.com/blog/2009/4/23/optimizing-url-generation-in-aspnet-mvc-part-2.html
It is a good idea to use the ActionLink method to write out links as your coworker says, that way they will always match your routes.
In your current case the reason it is writing out the method is because it is based on the default routing. You can fix this by adding another route above the default one in the Global.asax. You just need to stipulate the format you want like this:
routes.MapRoute(
"Recruiter",
"Recruiter/{id}/{name}",
new { controller = "Recruiter", action = "Details" }
);
MVC will work through your routes in the order they are registered so putting this before the default will make it use your route instead.
EDIT:
You might find this route debugging tool useful.

Resources