I’m trying to set up some routes for my ASP.NET MVC 5 project.
- I defined custom routes to get nice blog post permalinks – those seem to be working fine
- I added a XmlRpc Handler (similar to how it’s done in Mads' Miniblog and Scott’s post)
Now I have some strange behavior:
/Home/About
is routed correctly/Home/Index
gets routed to/XmlRpc?action=Index&controller=Blog
/HOme/Index
works (yes I discovered that due to a typo) – I always thought routes are case insensitive?- Using
Url.Action("Foo","Bar")
also creates/XmlRpc?action=Foo&controller=Bar
This is my RouteConfig
file:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.Add("XmlRpc", new Route("XmlRpc", new MetaWeblogRouteHandler()));
routes.MapRoute("Post", "Post/{year}/{month}/{day}/{id}", new {controller = "Blog", action = "Post"}, new {year = @"\d{4,4}", month = @"\d{1,2}", day = @"\d{1,2}", id = @"(\w+-?)*"});
routes.MapRoute("Posts on Day", "Post/{year}/{month}/{day}", new {controller = "Blog", action = "PostsOnDay"}, new {year = @"\d{4,4}", month = @"\d{1,2}", day = @"\d{1,2}"});
routes.MapRoute("Posts in Month", "Post/{year}/{month}", new {controller = "Blog", action = "PostsInMonth"}, new {year = @"\d{4,4}", month = @"\d{1,2"});
routes.MapRoute("Posts in Year", "Post/{year}", new {controller = "Blog", action = "PostsInYear"}, new {year = @"\d{4,4}"});
routes.MapRoute("Post List Pages", "Page/{page}", new {controller = "Blog", action = "Index"}, new {page = @"\d{1,6}"});
routes.MapRoute("Posts by Tag", "Tag/{tag}", new {controller = "Blog", action = "PostsByTag"}, new {id = @"(\w+-?)*"});
routes.MapRoute("Posts by Category", "Category/{category}", new {controller = "Blog", action = "PostsByCategory"}, new {id = @"(\w+-?)*"});
routes.MapRoute("Default", "{controller}/{action}/{id}", new {controller = "Blog", action = "Index", id = UrlParameter.Optional});
}
And that’s the definition of MetaWeblogRouteHandler
:
public class MetaWeblogRouteHandler : IRouteHandler
{
public IHttpHandler GetHttpHandler(RequestContext requestContext)
{
return new MetaWeblog();
}
}
Basically I’d like to have the usual ASP.NET MVC routing behavior (/controller/action) + my defined custom routes for permalinks + XML-RPC handling via the XmlRpc handler only at /XmlRpc.
Since the parameters are the same that are defined in the Default
route I tried to remove the route, but without success.
Any ideas?
Update:
When calling /Home/Index
the AppRelativeCurrentExecutionFilePath
is set to "~/XmlRpc"
so the XmlRpc route is legally chosen. Something seems to be messing around with the request?
Update2: The problem fixed itself in every but one case: when starting IE via Visual Studio for Debug it still fails. In every other case it now works (yes I checked browser cache and even tried it on a different machine to be sure; IE started from VS = fail, all other combinations are fine). Anyway, since it will now work for the end user I'm satisfied for the moment ;)
When you execute
Url.Action("Foo","Bar")
, MVC will create a collection of route values from your inputs (In that case action=Foo, controller=Bar) and it will then look at your routes, trying to match one that matches based on its segments and default values.Your XmlRpc route has no segments and no default values, and is the first one defined. This means it will always be the first match when generating urls using
@Url.Action
,@Html.ActionLink
etc.A quick way to prevent that route from being matched when generating urls would be adding a default controller parameter (using a controller name that you are sure you will never use). For example:
Now when you execute
Url.Action("Foo","Bar")
, you will get the expected/Bar/Foo
url, as "Bar" doesn´t match the default controller value in the route definition, "XmlRpc".However that seems a bit hacky.
A better option would be creating your own
RouteBase
class. This willonly care for the url/XmlRpc
, which will then be served usingMetaWeblogRouteHandler
and will be ignored when generating links using the Html and Url helpers:However, in the end you are creating a route just to run an
IHttpHandler
outside the MVC flow, for a single url. You are even struggling to keep that route from interferring with the rest of the MVC components, like when generating urls using helpers.You could then just add directly a handler for that module in the web.config file, also adding an ignore rule for
/XmlRpc
in your MVC routes:Using either of these 3 approaches, this is what I get:
/Home/Index
renders the Index view of theHomeController
/
renders the Index view of theBlogController
@Url.Action("Foo","Bar")
generates the url/Bar/Foo
@Html.ActionLink("MyLink","Foo","Bar")
renders the following html:<a href="/Bar/Foo">MyLink</a>
/XmlRcp
renders the a view describing the MetaWeblogHandler and its available methods, where there is a single method available (blog.index, taking no parameters and returning a string)In order for testing this, I have created a new empty MVC 5 application, adding the NuGet package xmlrpcnet-server.
I have created a
HomeController
and aBlogController
, both with an index action, and I have created the following MetaWeblog classes: