【问题标题】:Route gets mapped to parameters of different route路由被映射到不同路由的参数
【发布时间】:2014-05-23 07:16:10
【问题描述】:

我正在尝试为我的 ASP.NET MVC 5 项目设置一些路由。

  • 我定义了自定义路由以获得漂亮的博客文章永久链接——那些 似乎工作正常
  • 我添加了一个 XmlRpc 处理程序(类似于它的完成方式 在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/Index 时,AppRelativeCurrentExecutionFilePath 设置为 "~/XmlRpc",因此 合法 选择了 XmlRpc 路由。请求似乎有问题?

Update2: 除了一种情况外,该问题已自行解决:当通过 Visual Studio 启动 IE 进行调试时,它仍然失败。在其他所有情况下,它现在都可以工作(是的,我检查了浏览器缓存,甚至在另一台机器上尝试过,以确保;IE 从 VS = 失败开始,所有其他组合都很好)。无论如何,因为它现在适用于最终用户,所以我暂时感到满意;)

【问题讨论】:

    标签: c# asp.net-mvc asp.net-mvc-routing xml-rpc.net iroutehandler


    【解决方案1】:

    当您执行Url.Action("Foo","Bar") 时,MVC 将根据您的输入创建一组路由值(在这种情况下 action=Foo,controller=Bar),然后它会查看您的路由,尝试匹配一个基于它的段和默认值。

    您的 XmlRpc 路由没有段和默认值,并且是第一个定义的。这意味着在使用@Url.Action@Html.ActionLink 等生成 url 时,它将始终是第一个匹配项。

    在生成 url 时防止该路由匹配的一种快速方法是添加默认控制器参数(使用您确定永远不会使用的控制器名称)。例如:

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

    现在当您执行Url.Action("Foo","Bar") 时,您将获得预期的/Bar/Foo url,因为“Bar”与路由定义中的默认控制器值“XmlRpc”不匹配。

    不过,这似乎有点老套。

    更好的选择是创建自己的RouteBase 类。这将只关心 url /XmlRpc,然后将使用 MetaWeblogRouteHandler 提供服务,并且在使用 Html 和 Url 帮助程序生成链接时将被忽略:

    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 ...
    }
    

    但是,最终您创建的路由只是为了在 MVC 流之外运行 IHttpHandler,用于单个 url。您甚至在努力防止该路由干扰其他 MVC 组件,例如在使用帮助程序生成 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 ...         
    }
    

    使用这三种方法中的任何一种,这就是我得到的:

    • /Home/Index 呈现HomeController 的索引视图

    • / 呈现BlogController 的索引视图

    • @Url.Action("Foo","Bar") 生成网址/Bar/Foo

    • @Html.ActionLink("MyLink","Foo","Bar") 呈现以下 html:&lt;a href="/Bar/Foo"&gt;MyLink&lt;/a&gt;

    • /XmlRcp 呈现描述 MetaWeblogHandler 及其可用方法的视图,其中只有一个可用方法(blog.index,不带参数并返回字符串)


    为了对此进行测试,我创建了一个新的空 MVC 5 应用程序,添加了 NuGet 包 xmlrpcnet-server

    我创建了一个HomeController 和一个BlogController,都带有索引操作,并且我创建了以下 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();
        }
    }
    

    【讨论】:

    • 感谢您的广泛回答!我正在尝试实现你的最后一个版本,因为这毕竟是我真正想要实现的。 /Home/Index 仍然存在同样的问题(/Home 有效)。我很快开始了第二个项目,并创建了与您描述的相同的最小版本,您的解决方案确实可以正常工作。所以在我的主要项目中的任何地方都必须有一个糟糕的设置。您知道缺陷可能在哪里,或者我可以如何调试路由过程吗?
    • 最明显的选择是开始向基本项目添加更多功能,特别是全局过滤器、额外的 httpHandlers、NuGet 包……如果您尝试第二种方法(创建自定义 RouteBase)你也有/Home/Index 的问题吗?在这种情况下,您可以在其GetRouteData 方法中设置断点并检查 httpContext 中的请求对象,以防万一您发现那里有任何异常...
    • 利用 RouteBase 的好主意!我现在找到了问题,但没有解决方案:调用 /Home/Index 时,AppRelativeCurrentExecutionFilePath 设置为 "~/XmlRpc",因此选择了 XmlRpc 路由合法。至少我现在可以尝试找出请求被搞砸的原因。
    • 好吧,我终于找到了一个奇怪的问题,这个问题只有在从 Visual Studio 启动 IE 时才会出现。最终用户不会这样做,我可以解决它。再次感谢!
    猜你喜欢
    • 2019-03-29
    • 1970-01-01
    • 1970-01-01
    • 2017-03-25
    • 1970-01-01
    • 1970-01-01
    • 2013-05-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多