I'm using asp.net mvc 4 to build a web application.
To create url to an action I'm using ActionLink as follows:
#Html.ActionLink("Details", "Details", new { id=item.PrimaryKey })
item.PrimaryKey can be a string, so it can cointains dots or slashes or any other special character; When it contains dots or slashes i get an 404 error. ¿How can I avoid it?
I found a solution here
http://mrpmorris.blogspot.mx/2012/08/asp-mvc-encoding-route-values.html
but its complicated
¿Is there an easier solution to this?
I found a solution here
http://mrpmorris.blogspot.mx/2012/08/asp-mvc-encoding-route-values.html
but its complicated
That's because the problem you are attempting to solve is complicated. You may take a look at the following blog post from Scott Hanselman in which he explains the various challenges in doing this. I will summarize his conclusion:
After ALL this effort to get crazy stuff in the Request Path, it's
worth mentioning that simply keeping the values as a part of the Query
String (remember WAY back at the beginning of this post?) is easier,
cleaner, more flexible, and more secure.
So basically if your ids can contain any characters, they should be passed as query string parameters and not part of the Uri path.
But if you insist and want to have the ids as part of the Uri path you may be inspired by how StackOverflow does it. Look at the address bar of your browser now. You will see this:
https://stackoverflow.com/questions/15697189/special-characters-in-actionlink-asp-mvc
Notice how the url contains 2 tokens: the actual id and a SEO friendly name. Jeff Atwood showed a sample filter function they are using to generate those SEO friendly slugs. The slug is just for SEO purposes. You could replace it with whatever you want and get the same result:
https://stackoverflow.com/questions/15697189/foo-bar
You can use Server.UrlEncode() to encode it:
#Html.ActionLink("Details", "Details", new { id=Server.UrlEncode(item.PrimaryKey) })
reference to msdn with example
Related
I have developed a ASP.NET MVC application. I have a conroller with the name EmployeeController and it got a method called GetEmployeeByName. GetEmployeeByName() takes a name of type string as parameter.
So When I send a request like this, i get the data back :
someDomain:9999/Employee/GetEmployeeByName/Roger Federer
But if the name contains an '&' (you & me), I get a '400 Bad Request' as response from server.
someDomain:9999/Employee/GetEmployeeByName/you%20&%20me
Even if i encode it dont get a reposne back
someDomain:9999/Employee/GetEmployeeByName/you%20&%20me
What is the right way to encode such (data with special character) data?
What is the right way to encode such (data with special character) data?
The right way is to use a query string parameter and not be putting those things as part of the uri portion. Read the following blog post from Scott Hansleman. I will only quote hos conclusion:
After ALL this effort to get crazy stuff in the Request Path, it's
worth mentioning that simply keeping the values as a part of the Query
String (remember WAY back at the beginning of this post?) is easier,
cleaner, more flexible, and more secure.
As you can see in the blog post there are some hacky ways to make it work and circumvent IIS handling but it simply is not something that I would recommend you venturing into. Just put this name in the query string.
I have a news section where the pages resolve to urls like
newsArticle.php?id=210
What I would like to do is use the title from the database to create seo friendly titles like
newsArticle/joe-goes-to-town
Any ideas how I can achieve this?
Thanks,
R.
I suggest you actually include the ID in the URL, before the title part, and ignore the title itself when routing. So your URL might become
/news/210/joe-goes-to-town
That's exactly what Stack Overflow does, and it works well. It means that the title can change without links breaking.
Obviously the exact details will depend on what platform you're using - you haven't specified - but the basic steps will be:
When generating a link, take the article title and convert it into something URL-friendly; you probably want to remove all punctuation, and you should consider accented characters etc. Bear in mind that the title won't need to be unique, because you've got the ID as well
When handling a request to anything starting with /news, take the next part of the path, parse it as an integer and load the appropriate article.
Assuming you are using PHP and can alter your source code (this is quite mandatory to get the article's title), I'd do the following:
First, you'll need to have a function (or maybe a method in an object-oriented architecture) to generate the URLs for you in your code. You'd supply the function with the article object or the article ID and it returns the friendly URL with the ID and the friendly title.
Basically function url(Article $article) => URL.
You will also need some URL rewriting rules to remove the PHP script from the URL. For Apache, refer to the mod_rewrite documentation for details (RewriteEngine, RewriteRule, RewriteCond).
I am trying to write a route that matches the following URL format:
/category1/category2/S/
where the number of categories is unknown, so there could be 1 category or there could be 10 (1..N).
I cannot use a catch all becuase the categories are not at the end of the URL.
I am actually routing to a web form here (using Phil Haack's example http://haacked.com/archive/2008/03/11/using-routing-with-webforms.aspx), but that is beside the point really.
Any ideas?
To be honest, I found the answer here to be more useful: Using the greedy route parameter in the middle of a route definition
The blog post linked to in the question was extremely useful: http://www.thecodejunkie.com/2008/11/supporting-complex-route-patterns-with.html
I think it's impossible but you could try work around it using this route:
{categories}/S
Then split the categories using the '/' character yourself.
I made a site where I just fixed it to 1-3 categories by registering 3 routes, but I had to work around a lot of things and wasn't really happy with it afterwards.
EDIT: Using S/{*categories} will catch the categories. You can only use it at the end of the URL.
Exactly what you need(ed)
This is a long time lost shot, but I seem to have exactly what you need. I've written a GreedyRoute class that allows greedy segment anywhere in the URL (at the beginning, in the middle or at the end - which is already supported).
You can read all details on my blog as well as getting the code of this particular class.
The main thing is it supports any of these patterns:
{segment}/{segment}/{*segment}
{segment}/{*segment}/{segment}
{*segment}/{segment}/{segment}
It doesn't support multiple greedy segments though (which is of course possible as well but has some restrictions that should be obeyed in that scenario), but I guess that's a rare example where that could be used.
I would like to develop URL's which look like the following:
http://mysite.com/products/1/best-product-in-the-world
Where all i need to get to the proper record is the following route:
http://mysite.com/products/1
When I add the product description piece to the URL ("best-product-in-the-world") I get URL encoding issues. I've tried to use Server.UrlEncode when constructing this portion of my URL in an ActionLink(...):
<%= Html.ActionLink(item.Subject, "../Post/Detail",
new { id = item.ID,
descriptiveUrl = Server.UrlEncode(Product.ShortDescription) },
new { rel = "canonical",
title = Product.ShortDescription,
#class = "product-hyperlink" })%>
But this renders regularly encoded elements for special characters and spaces, much like the following:
http://localhost:2392/Products/Detail/1/best+product+in+the+world253f
...which creates a 400, bad request exception. Not sure I've done the question justice, but can provide further clarification if need be.
Update: this post's URL is as follows, and i'm trying to do something very similar!
http://stackoverflow.com/questions/1148955/creating-search-engine-friendly-urls-in-asp-net-mvc
In a deeper Google search, I found the following link for generating slugs:
http://www.intrepidstudios.com/blog/2009/2/10/function-to-generate-a-url-friendly-string.aspx
Thanks #Rob and #Coding the Wheel for giving me the terminology I really needed to find this answer!
A simple option would be to add a property to your model object with an accessor that normalises the appropriate field (short description in this case) down to a suitable "slug"; that is, the bit of junk text after the identifier. You then use this when constructing the URI.
The normalisation process might be as simple as removing any non-alphanumeric characters and replacing spaces with hyphens.
The standard practice here is to store a 'slug' with each post that will function as the post's outward-facing URL. For example, your slug for the above post would be:
best-product-in-the-world
A decent CMS will do this for you automatically, and allow you to tweak the slug before saving.
Is there a specific pattern that developers generally follow? I never really gave it much thought before in my web applications, but the ASP.NET MVC routing engine pretty much forces you to at least take it into consideration.
So far I've liked the controller/action/index structure (e.g. Products/Edit/1), but I'm struggling with more complex urls.
For instance, let's say you have a page that lists all the products a user has in their account. How would you do it? Off the top of my head I can think of the following possibilities for a listing page and an edit page:
User/{user id}/Products/List, User/{user id}/Products/Edit/{product id}
User/{user id}/Products, User/{user id}/Products/{product id}
Products?UserID={user id}, Products/Edit/{product id}
I'm sure there are plenty of others that I'm missing. Any advice?
I like RESTful, user friendly and hackable URLs.
What does this mean? Lets start with user friendly URLs. To me a user friendly URL is something easy to type and easy to remember /Default.aspx?action=show&userID=140 doesn't meet any of these requirements. A URL like `/users/troethom´ seems logical though.
This leads to the next point. A hackable URL is an URL that the user can modify and still get presented with a result. If the URL is hackable and the URL for my profile is /users/troethom it would be safe to remove my user name to get a list of users (/users).
Using RESTful URLs is pretty similar to the ideas behind my other suggestions. You are designing URLs for a user and not for a machine and therefore the URL has to relate to the content and not the the technical back-end of your site. An URL as ´/users´ makes more sense than ´/users/list´ and an URL as ´/category/programming/javascript´ (representing the subcategory 'javascript' in the category 'programming' is better than ´/category/show/12´.
It is indeed more difficult to omit IDs, but in my world it is worth the effort.
Also consult the Understanding URIs section on W3C´s Common HTTP Implementation Problems. It has a list of common pitfalls when designing URIs. Another good resource is Resourceful Vs Hackable Search URLs.
You may want to take a look at the question "Friendly url scheme?".
Particularly, Larry.Smithmier's answer provided a list of common URL schemes when using MVC in ASP.NET.
Also, you may consider using different verbs to reuse the same routes for different actions. For example, a GET request to "Products/Edit/45" would display the product editor, whereas a POST to the same url would update the product. You can use the AcceptVerb attribute to accomplish this:
[AcceptVerb("GET")]
public ActionResult Edit(int id)
{
ViewData["Product"] = _products.Get(id);
return View();
}
[AcceptVerb("POST")]
public ActionResult Edit(int id, string title, string description)
{
_products.Update(id, title, description);
TempData["Message"] = "Changes saved successfully!";
return RedirectToAction("Edit", new { id });
}
Bill de hÓra wrote a very good essay entitled Web resource mapping criteria for frameworks that is well worth a read.
To add to troethom's comments, RESTful generally also means that, for example, to create a new user you would PUT a representation to /users/newusername
RESTful basically uses the 5 standard HTTP Methods (GET, PUT, POST, DELETE, HEAD) for controlling/accessing content.
Ok, this isn't easy for a web browser, but you can always use overloaded POST (post to /users/username with a representation of a user to change some of the details, etc.
Its a good way of doing things, I'd reccommend reading RESTFul Web services to get a better understanding :D (and it's a darn good book!)
I've seen two main accepted ways to approach this topic...
One is described in the MvcContrib project documentation
and the other one is described in a blog post by Stephen Walther (which I personally prefer).