4

我正在嘗試爲ASP.NET MVC 5項目設置一些路由。路由被映射到不同路由的參數

  • 我定義的自定義路線得到很好的博客文章的永久鏈接 - 那些 似乎是工作的罰款
  • 我添加了一個XML-RPC處理程序(類似於它是如何做的Mads' MiniblogScott’s post

現在我有一些奇怪的行爲:

  • /Home/About路由正確
  • /Home/Index被路由到/XmlRpc?action=Index&controller=Blog
  • /HOme/Index作品(是的,我 發現,由於錯字) - 我一直以爲是航線情況 不敏感?
  • 使用Url.Action("Foo","Bar")也創造/XmlRpc?action=Foo&controller=Bar

這是我RouteConfig文件:

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});    
} 

這就是的MetaWeblogRouteHandler定義:

public class MetaWeblogRouteHandler : IRouteHandler 
{ 
    public IHttpHandler GetHttpHandler(RequestContext requestContext) 
    { 
     return new MetaWeblog(); 
    } 
} 

基本上我想有平常ASP.NET MVC路由行爲(/ controller/action)+我定義的自定義路由永久鏈接+僅通過/ XmlRpc通過XmlRpc處理程序處理XML-RPC。

由於參數與在Default路線中定義的參數相同,因此我嘗試刪除路線,但沒有成功。
任何想法?

更新:
當調用/Home/IndexAppRelativeCurrentExecutionFilePath設置爲"~/XmlRpc"所以XML-RPC的路線是法律選擇。東西似乎在與請求搞混了嗎?

Update2:這個問題在除了一種情況之外的每一種情況下都解決了問題:當通過Visual Studio啓動IE以進行調試時,它仍然失敗。在所有其他情況下,它現在可以工作(是的,我檢查了瀏覽器緩存,甚至在不同的機器上嘗試過它; IE從VS開始=失敗,所有其他組合都沒問題)。無論如何,因爲它現在可以爲最終用戶工作,所以我現在很滿意;)

回答

5

當您執行Url.Action("Foo","Bar")時,MVC會根據您的輸入創建一組路由值(在這種情況下,action = Foo,controller =酒吧),然後它會查看您的路線,嘗試匹配基於其細分和默認值匹配的路線。

您的XmlRpc路由沒有段且沒有默認值,並且是第一個定義的路由。這意味着它將始終是使用@Url.Action@Html.ActionLink等生成網址時的首個匹配項。

在生成URL時防止路由匹配的一種快速方法是添加默認控制器參數(使用控制器名稱,您肯定永遠不會使用它)。例如:

routes.Add("XmlRpc", new Route("XmlRpc", new RouteValueDictionary() { { "controller", "XmlRpc" } }, new MetaWeblogRouteHandler())); 

現在當你執行Url.Action("Foo","Bar"),你會得到預期的/Bar/Foo網址,如「酒吧」 doesn't匹配路線定義,「XMLRPC」的默認控制器值。

但是,這似乎有點hacky。

更好的選擇是創建自己的RouteBase類。這willonly照顧URL /XmlRpc,這將然後使用MetaWeblogRouteHandler提供服務以及使用HTML和網址助手鍊接時將被忽略:

public class XmlRpcRoute : RouteBase 
{ 
    public override RouteData GetRouteData(HttpContextBase httpContext) 
    { 
     //The route will only be a match when requesting the url ~/XmlRpc, and in that case the MetaWeblogRouteHandler will handle the request 
     if (httpContext.Request.AppRelativeCurrentExecutionFilePath.Equals("~/XmlRpc", StringComparison.CurrentCultureIgnoreCase)) 
      return new RouteData(this, new MetaWeblogRouteHandler()); 

     //If url is other than /XmlRpc, return null so MVC keeps looking at the other routes 
     return null; 
    } 

    public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values) 
    {    
     //return null, so this route is skipped by MVC when generating outgoing Urls (as in @Url.Action and @Html.ActionLink) 
     return null; 
    } 
} 

public static void RegisterRoutes(RouteCollection routes) 
{ 
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); 
    //Add the route using our custom XmlRpcRoute class 
    routes.Add("XmlRpc", new XmlRpcRoute()); 

    ... your other routes ... 
} 

但是,到底要創建一個路由只是爲了運行IHttpHandler以外的MVC流,爲一個單一的網址。你甚至努力保持這條路線不會干擾其他MVC組件,就像使用helper生成url一樣。

然後,您可以只需直接添加處理程序在web.config文件模塊,還增加了一個忽略規則在你的MVC路線/XmlRpc

<configuration> 
    ... 
    <system.webServer> 
    <handlers> 
     <!-- Make sure to update the namespace "WebApplication1.Blog" to whatever your namespace is--> 
     <add name="MetaWebLogHandler" verb="POST,GET" type="WebApplication1.Blog.MetaWeblogHandler" path="/XmlRpc" /> 
    </handlers> 
    </system.webServer> 
</configuration> 

public static void RegisterRoutes(RouteCollection routes) 
{ 
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); 
    //Make sure MVC ignores /XmlRpc, which will be directly handled by MetaWeblogHandler 
    routes.IgnoreRoute("XmlRpc"); 

    ... your other routes ...   
} 

使用這兩種方法3,這是我得到什麼:

  • /Home/Index呈現的HomeController

  • 索引視圖/呈現的BlogController

  • @Url.Action("Foo","Bar") Index視圖生成鏈接/Bar/Foo

  • @Html.ActionLink("MyLink","Foo","Bar")呈現下面的HTML:<a href="/Bar/Foo">MyLink</a>

  • /XmlRcp呈現描述MetaWeblogHandler及其可用的方法,其中的圖有是一種可用的方法(blog.index,不帶參數並返回字符串)


爲了測試這一點,我創建了一個新的空MVC 5應用程序,添加NuGet包xmlrpcnet服務器

我創建了一個HomeControllerBlogController,都與一個索引動作,我已經創建了下面的MetaWeblog類:

public interface IMetaWeblog 
{ 
    [XmlRpcMethod("blog.index")] 
    string Index();   
} 

public class MetaWeblogHandler : XmlRpcService, IMetaWeblog 
{ 
    string IMetaWeblog.Index() 
    { 
     return "Hello World"; 
    }   
} 

public class MetaWeblogRouteHandler : IRouteHandler 
{ 
    public IHttpHandler GetHttpHandler(RequestContext requestContext) 
    { 
     return new MetaWeblogHandler(); 
    } 
} 
+0

感謝廣泛的答案!我試圖實現你的最後一個版本,因爲這是我真正想要實現的。而且'/ Home/Index'('/ Home'作品)還存在同樣的問題。我很快開始了第二個項目,並創建了與您所描述的相同的最小版本,並且您的解決方案也能正常工作所以在我的主要項目的任何地方都必須有一個糟糕的設置。你有沒有任何想法可以解決這個缺陷,或者我可以如何調試路由過程? – marce

+0

最明顯的選擇是開始向基本項目添加更多功能,特別是像全局過濾器,附加httpHandlers,NuGet軟件包......如果嘗試第二種方法(創建自定義RouteBase),是否也有問題'/首頁/ Index'?在這種情況下,您可以在其GetRouteData方法中設置一個斷點並檢查httpContext中的請求對象,以防萬一您在那裏發現任何異常... –

+0

利用RouteBase的好主意!我現在發現了這個問題,但沒有解決方案:當調用'/ Home/Index'時,'AppRelativeCurrentExecutionFilePath'設置爲'「〜/ XmlRpc」',所以XmlRpc路由被選中。至少我現在可以嘗試追查爲什麼請求會搞砸。 – marce