71

Question:

I am creating a wiki software, basically a clone of wikipedia/mediawiki, but in ASP.NET MVC (the MVC is the point, so don't recommend me ScrewTurn).

Now I have a question:

I use this route mapping, to route a URL like:
http://en.wikipedia.org/wiki/ASP.NET

 routes.MapRoute(
 "Wiki", // Routenname
 //"{controller}/{action}/{id}", // URL mit Parametern
 "wiki/{id}", // URL mit Parametern
 new { controller = "Wiki", action = "dbLookup", id = UrlParameter.Optional } // Parameterstandardwerte
 );

Now it just occured to me, that there might be titles like 'AS/400':
http://en.wikipedia.org/wiki/AS/400

Incidentially, there is also this one (title 'Slash'):
http://en.wikipedia.org/wiki//

And this one:
http://en.wikipedia.org/wiki//dev/null

Overall, Wikipedia seems to have a list of interesting titles like this: http://en.wikipedia.org/wiki/Wikipedia:Articles_with_slashes_in_title

How do I make routes like this route correctly ?

Edit:
Something like:
If the URL starts with /Wiki/, and if it doesn't start with /wiki/Edit/ (but not /Wiki/Edit) then pass all the rest of the URL as Id.

Edit:
Hmm, just another problem: How can I route this one:
http://en.wikipedia.org/wiki/C&A

Wikipedia can...

Edit:
According to wikipedia, due to clashes with wikitext syntax, only the following characters can never be used in page titles (nor are they supported by DISPLAYTITLE):

# < > [ ] | { }

http://en.wikipedia.org/wiki/Wikipedia:Naming_conventions_(technical_restrictions)#Forbidden_characters

Edit:
To allow * and &, put

<httpRuntime requestPathInvalidCharacters="" />

into section <system.web> in file web.config

(Found here: http://www.christophercrooker.com/use-any-characters-you-want-in-your-urls-with-aspnet-4-and-iis)

Erik Philips
54.9k11 gold badges133 silver badges158 bronze badges
asked Jun 13, 2011 at 9:33
2
  • Can you change your routing parameter character to something "more usual", like a question mark, or a comma... something is NOT valid in a title? Commented Jun 13, 2011 at 9:39
  • 1
    ASP.NET MVC routing isn't your only problem. Try topics like "LPT", "SQL*plus", "US$", "C#" etc. A lot of them will be caught by IIS. You better think about escaping some of them. Commented Jun 13, 2011 at 10:40

4 Answers 4

107

You could use a catchall route to capture everything that follows the wiki part of the url into the id token:

routes.MapRoute(
 "Wiki",
 "wiki/{*id}",
 new { controller = "Wiki", action = "DbLookup", id = UrlParameter.Optional }
);

Now if you have the following request: /wiki/AS/400 it will map to the following action on the Wiki controller:

public ActionResult DbLookup(string id)
{
 // id will equal AS/400 here
 ...
}

As far as /wiki// is concerned I believe you will get a 400 Bad Request error from the web server before this request ever reaches the ASP.NET pipeline. You may checkout the following blog post.

answered Jun 13, 2011 at 9:37
Sign up to request clarification or add additional context in comments.

9 Comments

Nice, that works, but what about when I want to excempt /wiki/Edit/ArticleTitle from this rule ? (but that shouldn't excemp /wiki/Edit)
@Quandary, I don't think you could exempt with a catchall rule. You could try defining another route before the one I showed which looks like this wiki/Edit/{*id}.
@Darin: OK, works perfectly. In Edit, that requires to catch id isnullorempty and redirect to action action dbLookup with id as Edit.
@Darin: if in the Edit action, I do a if (string.IsNullOrEmpty(id)) return RedirectToAction("dbLookup", "Wiki", new { id = "Edit" }); then I enter a infinite loop... why ?
@Quandary, I guess that RedirectToAction("dbLookup", "Wiki", new { id = "Edit" }) resolves to the Edit action once again.
|
31

in Attribute Routing in mvc i had the same problem having / in string abc/cde in HttpGet

 [Route("verifytoken/{*token}")]
 [AllowAnonymous]
 [HttpGet]
 public ActionResult VerifyToken(string token)
 {
 //logic here
 }

so you have to place * because after this it will be considered as parameter

answered Feb 13, 2017 at 7:33

5 Comments

awesome. this is the best and easiest solution :)
This seems to work for one slash, but not two in a row. any ideas there?
@Usman What about if you have another route that is [Route("verifytoken/{token}/something")]? Wouldn't the wildcard potentially have conflicts with this route if there are forward slashes? Is there another way to do this for this use case?
You are a hero! I was trying to create a custom url with slashes without any luck, no matter what i tried i was getting /Admin/Customers/Edit?id=1 instead of teh desired output /Admin/Customers/Edit/1. That asterisk did the trick! Thanks once again
Great answer. it works in HttpMethodAttribute as well. (.net core 3.1) [HttpGet("verifytoken/{*token}")] It works for more than one slash as well. e.g: localhost:44352/api/verifytoken/1234/12/23/rebase.pdf token = "1234/12/23/rebase.pdf"
5

@Darin: Well, that much is obvious, the question is: Why ? controller + action + id are given, it's like it's passing all these to routing again... – Quandary Jun 13 '11 at 17:38

Quandry - maybe you have already figured this out since your question is over a year old, but when you call RedirectToAction, you are actually sending an HTTP 302 response to the browser, which causes the browser to make a GET request to the specified action. Hence, the infinite loop you are seeing.

See: Controller.RedirectToAction Method

Nikhil
16.2k20 gold badges66 silver badges81 bronze badges
answered Jun 22, 2012 at 20:24

1 Comment

Server.Transfer resolves this: stackoverflow.com/questions/799511/…
-3

Still as an option write in the file Global.asax:

 var uri = Context.Request.Url.ToString();
 if (UriHasRedundantSlashes(uri))
 {
 var correctUri = RemoveRedundantSlashes(uri);
 Response.RedirectPermanent(correctUri);
 }
 }
 private string RemoveRedundantSlashes(string uri)
 {
 const string http = "http://";
 const string https = "https://";
 string prefix = string.Empty;
 if (uri.Contains(http))
 {
 uri = uri.Replace(http, string.Empty);
 prefix = http;
 }
 else if (uri.Contains(https))
 {
 uri = uri.Replace(https, string.Empty);
 prefix = https;
 }
 while (uri.Contains("//"))
 {
 uri = uri.Replace("//", "/");
 }
 if (!string.IsNullOrEmpty(prefix))
 {
 return prefix + uri;
 }
 return uri;
 }
 private bool UriHasRedundantSlashes(string uri)
 {
 const string http = "http://";
 const string https = "https://";
 if (uri.Contains(http))
 {
 uri = uri.Replace(http, string.Empty);
 }
 else if (uri.Contains(https))
 {
 uri = uri.Replace(https, string.Empty);
 }
 return uri.Contains("//");
 }
Arseni Mourzenko
52.7k35 gold badges119 silver badges213 bronze badges
answered Mar 20, 2017 at 18:40

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.