Handle dynamic number of optional URL parameters in IIS rewrite rules - asp.net

My scenario is as follows: a venue can be part of multiple categories and users can also add filters on multiple category types, so my URLs now are like:
/venues/beaches/boats/themeparks
(this will display all venues that are beaches AND boats AND themeparks)
/venues/beaches/boats
/venues etc.
So the number of different venue types (beaches, boats, themeparks etc) is both dynamic AND optional. How can I setup my rewrite rules that the category querystring parameter holds all the different venue types or preferably the category parameter is added multipe times and if no venuetype is provided category will just be empty/null?
So for URL: /venues/beaches/boats/themeparks
I'd get this rewritten URL: search.aspx?category=beaches&category=boats&category=themeparks
And for URL: /venues
I'd get this rewritten URL: search.aspx?category= (or fine too would be: search.aspx)
I now just have this:
<rule name="venue types">
<match url="^venues/([a-zA-Z0-9-+']+)$"/>
<action type="Rewrite" url="search.aspx?category={R:1}"/>
</rule>
update
I went with the below suggestion of #Arindam Nayak.
I installed https://www.nuget.org/packages/Microsoft.AspNet.FriendlyUrls.Core/ and manually created a RouteConfig.vb file in App_Start folder. I added (as a test):
Public NotInheritable Class RouteConfig
Private Sub New()
End Sub
Public Shared Sub RegisterRoutes(routes As RouteCollection)
Dim settings = New FriendlyUrlSettings()
settings.AutoRedirectMode = RedirectMode.Permanent
routes.EnableFriendlyUrls(settings)
routes.MapPageRoute("", "test", "~/contact.aspx")
End Sub
End Class
And in global.aspx.vb I added:
Sub Application_Start(ByVal sender As Object, ByVal e As EventArgs)
RouteConfig.RegisterRoutes(RouteTable.Routes)
End Sub
When I go to www.example.com/test, it does now correctly redirect me to contact.aspx. (Be aware: URL Rewriting - so rules in web.config or rewriteRules.config file - take precedence over RouteConfig.vb!)
I'm almost there, so this www.example.com/test redirects correctly to file contact.aspx
But this www.example.com/test/boats/outside/more/fields/are/here, throws a 404 error:
update 2
I added logging to routeConfig.vb:
GlobalFunctions.Log("1")
Dim settings = New FriendlyUrlSettings()
GlobalFunctions.Log("2")
settings.AutoRedirectMode = RedirectMode.Permanent
GlobalFunctions.Log("3")
routes.EnableFriendlyUrls(settings)
GlobalFunctions.Log("4")
routes.MapPageRoute("", "test", "~/contact.aspx")
GlobalFunctions.Log("5")
And these lines are all executed. Now something strange is happening:
routeConfig.vb seems to only be executed once. So:
I build my app.
I goto /test URL
the lines are logged and I arrive on the contact.aspx page
I refresh the /test page, NO lines are logged
And I also tried:
I build my app.
I goto /test/boats/outside/more/fields/are/here URL
the lines are logged
I get the aforementioned 404 error
I refresh the page, nothing is logged anymore
So it seems routeConfig is only ever hit once (at applicationstart?) and then never hit again. And for request /test/boats/outside/more/fields/are/here it arrives at routeConfig.vb file, but does not show contact.aspx for some reason...
update 3
I found that when I explicitly define the routes, it does work, like so:
routes.MapPageRoute("", "test", "~/contact.aspx")
routes.MapPageRoute("", "test/123", "~/contact.aspx")
So now URL /test and /test/123 work, but that is not dynamic at all as I just want to match on /test and then get the FriendlyUrlSegments.
I can't post the code online, so if it helps, here's my solution explorer:
What can I do?

To have such kind of SEO friendly URL you need to install “Microsoft.AspNet.FriendlyUrls” nuget package.
Open package manager console – Help. Then type following –
Install-Package Microsoft.AspNet.FriendlyUrls
Then it will automatically add following in RouteConfig.cs.
public static class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
var settings = new FriendlyUrlSettings();
settings.AutoRedirectMode = RedirectMode.Permanent;
routes.EnableFriendlyUrls(settings);
}
}
For you case, you need to add following to RouteConfig.cs.
routes.MapPageRoute("", "venues", "~/venues.aspx");
So when you hit url http://www.example.com/venues/beaches/boats/themeparks or http://www.example.com/venues/beaches, it will hit venues.aspx. In venues.aspx.cs, page_load event you need to have following code.
IList<String> str = Request.GetFriendlyUrlSegments();
For case-1, str will be ['beaches','boats','themeparks'] and for case-2 it will be ['beaches'].
For more info you can refer to my blog or similar SO answer here - Reroute query string using friendlyUrl
Let me know,if you face any issue or still your issue is unresolved.

Related

ASP.net MVC 5 Route with two parameter

I want create web application with 2 parameter. Add this Code to RegisterRoutes function:
routes.MapRoute(
"pageroute",
"page/{pageid}/{pagename}",
new { controller = "page", action = "Index", pageid = "", pagename = "" }
);
and add this method in pageController:
public ActionResult Index(int pageid,string pagename)
{
return View();
}
Now when i running application with this parameter
http://localhost:1196/page/4/Pagename
Application run successfully but when running with this parameter
http://localhost:1196/page/4/Pagename.html
Application return 404 error
HTTP Error 404.0 - Not Found
The resource you are looking for has been removed, had its name changed, or is temporarily unavailable.
while add .html in parameter return 404 error. why?
Because by default HTML files are not being served through MVC/IIS.
Your application looks for a physical file named Pagename.html and cannot find it there. Hence - 404.
To make it work, you need to setup your IIS to catch requests for files with HTML extension and pass this request to MVC.
EDIT: Here is a similar question where OP found a solution by switching "Managed Pipeline Mode" to "Classic".
Try changing the Route to:
routes.MapRoute(
"pageroute",
"page/{pageid}/{*pagename}",
new { controller = "page", action = "Index", pageid = "", pagename = "" }
);
This will then match everything as in page/1/* so the .html should go via this route.
I was unable to reproduce an issue where a .html file gave a 404 using a scenario similar to the question, so there may be some other routing issue or IIS configuration causing this.

ASP.NET MVC5 Customised Inbound Routing

I'm "playing" around with custom inbound URL routing and have came across a problem.
When I pass my custom route a URL to examine, that ends in *.+, my class is not fired when i submit the request.
An example URL would be "~/old/windows.html"
When I step through this in the debugger, my RouteBase implementation doesn't fire. If i edit the url that i pass to the constructor of my route to try to match against "~/old/windows", my implemetation is fired as expected.
Again, If i change the url ro examine to "~/old/windows." the problem reoccurs.
My Route Implementation is below :-
public class LegacyRoute : RouteBase
{
private string[] _urls;
public LegacyRoute(string[] targetUrls)
{
_urls = targetUrls;
}
public override RouteData GetRouteData(HttpContextBase httpContext)
{
RouteData result = null;
string requestedURL = httpContext.Request.AppRelativeCurrentExecutionFilePath;
if (_urls.Contains(requestedURL, StringComparer.OrdinalIgnoreCase))
{
result = new RouteData(this, new MvcRouteHandler());
result.Values.Add("controller", "Legacy");
result.Values.Add("action","GetLegacyURL");
result.Values.Add("legacyURL", requestedURL);
}
return result;
}
public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
{
return null;
}
}
In the RoutesConfig file I have registered my route like so :-
routes.MapMvcAttributeRoutes();
routes.Add(new LegacyRoute(new[]{"~/articles/windows.html","~/old/.Net_1.0_Class_Library"}));
Can anyone point out why there is a problem?
By default, the .html extension is not handled by .NET, it is handled by IIS directly. You can override by adding the following section in Web.config under <system.webServer> -
<handlers>
<add name="HtmlFileHandler" path="*.html" verb="GET" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>
As pointed out here. The above will route EVERY .html file request to .NET, you might want to be more specific by providing a more complete path if you don't want your routing to handle every .html file.
I've found the problem, and I'm sure this will help out a lot of fellow developers.
The problem is with IIS Express that is running via Visual Studio.
There is a module configured in the applicationhost.config called :-
UrlRoutingModule-4.0
This is how it looks in file :-
<add name="UrlRoutingModule-4.0" type="System.Web.Routing.UrlRoutingModule" preCondition="managedHandler,runtimeVersionv4.0" />
You need to set the preCondition Parameter to "".
To do this :-
Run you app via Visual Studio
Right click on IIS Express in your system tray, select "Show All Applications"
Click on the project you wish to edit, then click the config URL.
Open the file with Visual Studio, Locate the module and ammend.
Hope this helps anyone else, who ran into a similar problem.

ASP.NET 'Friendly URL' module - not working for root URL

I am successfully using the 'Friendly URL' module in ASP.NET 4.5
In route config I can add a route like this:
routes.MapPageRoute("mypage", "mypage/{mypageName}", "~/mypage.aspx");
for a URL like this:
mysite.com/mypage/hello
in the page 'mypage.aspx' I can get URL segments like this:
using Microsoft.AspNet.FriendlyUrls;
// Get URL segments
IList<string> segments = Request.GetFriendlyUrlSegments();
if (segments.Count > 0)
{
// Get first segment
string url = segments[0];
}
However, I cannot get this working for root URL's. e.g. 'my site.com/ttee'
I want to get 'ttee' and pass it into a page. But 'Request.GetFriendlyUrlSegments()' returns 0 for the root.
How best can I do this?
routes.MapPageRoute("mypage", "mypage/{mypageName}", "~/mypage.aspx");
This will work only for URLs in this format:
www.example.com/mypage/changingparthere
If you want to make it
www.example.com/changablemypage
Set it to:
routes.MapPageRoute("mypage", "{mypageName}", "~/mypage.aspx");
But as you can see, it will catch literally everything. So make sure it is the last routing on Global.asax.

Dynamic Routing with Web API

I have a WebAPI controller with a Get method as follows:
public class MyController : ApiController
{
public ActionResult Get(string id)
{
//do some stuff
}
}
The challenge is that I am attempting to implement WebDAV using Web API. What this means is that as a user browses down a folder structure the URL will change to something like:
/api/MyController/ParentFolder1/ChildFolder1/item1.txt
Is there a way to route that action to MyController.Get and extract out the path so that I get:
ParentFolder1/ChildFolder1/item1.txt
Thanks!
"Dynamic" route is not a problem. Simply use wildcard:
config.Routes.MapHttpRoute(
name: "NavApi",
routeTemplate: "api/my/{*id}",
defaults: new { controller = "my" }
);
This route should be added before default one.
Problem is that you want to end URL with file extension. It will be interpreted as static request to .txt file.
In IIS7+ you can work around that by adding line in web.config:
<system.webServer>
<modules runAllManagedModulesForAllRequests="true" />
Don't forget that if you use MyController, then route segment is just "my"
Use the NuGet package "AttributeRouting Web API". You can specify specific routes for each action, including dynamic parameters.
I was just dealing with this so try it out, and come back if you need more help.

ASP.NET MVC 4 The resource cannot found error

I have an controller called "AuditoriaController" and at the _Layout.vbhtml I have a action link to this controller:
<li>#Html.ActionLink("Auditoria", "Index", "Auditoria")</li>
When I click at this link at the view I have this error message:
Server Error in '/' Application.
The resource cannot be found.
Description: HTTP 404. The resource you are looking for (or one of its dependencies) could have been removed, had its name changed, or is temporarily unavailable. Please review the following URL and make sure that it is spelled correctly.
Requested URL: /Auditoria/
Version Information: Microsoft .NET Framework Version:4.0.30319; ASP.NET Version:4.0.30319.17929
At the AuditoriaController I have this code:
Public Class AuditoriaController
Inherits System.Web.Mvc.Controller
'
' GET: /Auditoria
Function Index() As ActionResult
Return View(AuditoriaDB.GetAllItems())
End Function
End Class
Here is my Routes at the RouteConfig.vb
Public Shared Sub RegisterRoutes(ByVal routes As RouteCollection)
routes.IgnoreRoute("{resource}.axd/{*pathInfo}")
routes.MapRoute( _
name:="Default", _
url:="{controller}/{action}/{id}", _
defaults:=New With {.controller = "EscalaPrevisao", .action = "Index", .id = UrlParameter.Optional} _
)
End Sub
With other controllers not happen this problem. If I use this url: localhost:4802/Auditoria/Index the error does not happen.
Can anyone help me?
A 404 is returned when the controller class name is not what is expected.
Rename the "Home" default class to "Home1" and you'll see the exact same error. Validate there are no typos... It's almost guaranteed to be that.
Go to the Project properties page of the Web project and select the Web tab. In the Start Action section, set it to Specific Page, but leave the textbox empty.
Try rewriting the URL in the Application_BeginRequest() event in Global.Asax.cs
protected void Application_BeginRequest()
{
var originalPath = HttpContext.Current.Request.Path.ToLower();
if (originalPath.Equals("/"))
{
Context.RewritePath("Controller/Action");
}
}
Not an ideal solution but it works as a temporary one.
My controllers's namespace was incorrect (from moving files around). Once I fixed the namespace, all worked.
I Click the red highlighted check box and every thing went OK

Resources