属性路由显示为查询字符串

时间:2015-09-15 07:13:31

标签: c# asp.net asp.net-mvc-5 url-routing asp.net-mvc-routing

我正在使用属性路由,这是我映射其中一个创建操作的方式:

[Route("Create/{companyId:guid?}/{branchId:guid?}/{departmentId:guid?}")]
[Route("Create/{companyId:guid?}/{departmentId:guid?}")]
public async Task<ActionResult> Create(Guid? companyId, Guid? branchId, Guid? departmentId)

我还尝试了两个映射到相同操作名称的不同操作,如下所示:

[Route("Create/{companyId:guid?}/{branchId:guid?}/{departmentId:guid?}")]
public async Task<ActionResult> Create(Guid? companyId, Guid? branchId, Guid? departmentId)


[Route("Create/{companyId:guid?}/{departmentId:guid?}")]
[ActionName("Create")]
public async Task<ActionResult> CreateWithDepartmentOnly(Guid? companyId, Guid? departmentId)

它的设置是这样的,因为可能没有branchId并且您无法获得空参数。

仅在提供companyId时,或者同时提供companyIddepartmentId时才能正常工作。

提供branchId时,该ID将作为查询字符串添加,而不是路由参数。这种情况发生在我有两个不同的行为时,是否提供departmentId并不重要。

我的代码适用于所有场景,我只想清理URL并且没有任何查询字符串。任何解决方案或解决方法?

编辑1

我尝试了两种Slicksim的想法。

  • 设置路线的顺序无效
  • 命名路由就行了,但是只有提供了所有3个ID,省略了departmentId这是最后一个参数应该没有效果,而是忽略了branchId

编辑2

逻辑是这样的:

  • 公司可以设立分支机构和/或部门
  • 分行可以有部门
  • 部门可以有部门
  • 部门没有分支机构

根据您从哪里创建部门,这些ID在路线中。这是一个可行的解决方案吗?

[Route("Create/{companyId:guid}")]
[Route("Create/{companyId:guid}/{branchId:guid?}")]
[Route("Create/{companyId:guid}/{departmentId:guid?}")]
[Route("Create/{companyId:guid}/{branchId:guid?}/{departmentId:guid?}")]
public async Task<ActionResult> Create(Guid companyId, Guid? branchId, Guid? departmentId)

路由2和3是否正常工作,因为它们都具有相同数量和类型的参数。如果Id被放置在动作中正确命名的参数中,那么我就是金色的。

1 个答案:

答案 0 :(得分:1)

检查以下内容:

  1. 确保您已在RouteConfig中(或应用程序启动中的某个位置)调用routes.MapMvcAttributeRoutes()
  2. 确保您在 默认路线之前拨打了routes.MapMvcAttributeRoutes()
  3. public class RouteConfig
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
    
            // Add this to get attribute routes to work
            routes.MapMvcAttributeRoutes();
    
            routes.MapRoute(
                name: "Default",
                url: "{controller}/{action}/{id}",
                defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
            );
        }
    }
    

    此外,您可以通过选择参数来拍摄自己的脚。在路径上只能使用1个可选参数,它必须是最右边的参数。这里的第二个路由是无法访问的执行路径,因为所有3个第一个参数都是可选的。

    [Route("Create/{companyId:guid?}/{branchId:guid?}/{departmentId:guid?}")]
    [Route("Create/{companyId:guid?}/{departmentId:guid?}")]
    

    从技术上讲,你可以用一条路线做你想要的(我认为)。

    [Route("Create/{companyId:guid}/{departmentId:guid}/{branchId:guid?}")]
    public async Task<ActionResult> Create(Guid companyId, Guid departmentId, Guid? branchId)
    

    哪个匹配

    /Create/someCompanyId/someDepartmentId/someBranchId
    /Create/someCompanyId/someDepartmentId
    

    如果您确实希望所有参数都是可选的,最好的方法是使用查询字符串。路线不是为此类设计的,但如果你真的想使用路由去那里,请参阅this answer

    回答编辑2

    删除默认路由没有任何问题。但是,您的业务逻辑有点过于复杂,无法使默认路由工作。你的评估是正确的,第二和第三条路线彼此无法区分(即使你需要参数),因为模式是相同的。

    但.NET路由比MapRouteRoute属性单独提供的更灵活。

    此外,如果这些网址面向互联网(不在登录后面),这不是SEO友好的方法。搜索引擎展示位置在网址中使用公司,分支机构,部门和子部门 名称 会好得多。

    无论您是否决定坚持使用GUID方案,您都拥有一组唯一的URL,这是获得匹配所需的全部内容。您需要将每个可能的URL加载到可以根据传入请求进行检查的缓存中,然后您可以通过创建custom RouteBase as in this answer来手动提供路由值。您只需要更改PageInfo对象以保存所有3个GUID值并相应地更新路由。请注意,如果您进行了表连接并且想出了一个GUID来表示链接答案中的每个URL,那么它会更好(实现的逻辑更少)。

    public class PageInfo
    {
        public PageInfo()
        {
            CompanyId = Guid.Empty;
            BranchId = Guid.Empty;
            DepartmentId = Guid.Empty;
        }
    
        // VirtualPath should not have a leading slash
        // example: events/conventions/mycon
        public string VirtualPath { get; set; }
        public Guid CompanyId { get; set; }
        public Guid BranchId { get; set; }
        public Guid DepartmentId { get; set; }
    }
    

    GetRouteData

    result.Values["controller"] = "CustomPage";
    result.Values["action"] = "Details";
    
    if (!page.CompanyId.Equals(Guid.Empty))
    {
        result.Values["companyId"] = page.CompanyId;
    }
    
    if (!page.BranchId.Equals(Guid.Empty))
    {
        result.Values["branchId"] = page.BranchId;
    }
    
    if (!page.DepartmentId.Equals(Guid.Empty))
    {
        result.Values["departmentId"] = page.DepartmentId;
    }
    

    TryFindMatch

    Guid companyId = Guid.Empty;
    Guid branchId = Guid.Empty;
    Guid departmentId = Guid.Empty;
    
    Guid.TryParse(Convert.ToString(values["companyId"]), out companyId);
    Guid.TryParse(Convert.ToString(values["branchId"]), out branchId);
    Guid.TryParse(Convert.ToString(values["departmentId"]), out departmentId);
    
    var controller = Convert.ToString(values["controller"]);
    var action = Convert.ToString(values["action"]);
    
    
    if (action == "Details" && controller == "CustomPage")
    {
        page = pages
            .Where(x => x.CompanyId.Equals(companyId) && 
                x.BranchId.Equals(branchId) && 
                x.DepartmentId.Equals(departmentId))
            .FirstOrDefault();
        if (page != null)
        {
            return true;
        }
    }
    return false;