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

[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放置在操作中正确命名的参数中,那么我很高兴。

最佳答案

检查以下内容:


确保已在RouteConfig(或应用程序启动中的某个位置)中调用了routes.MapMvcAttributeRoutes()
确保已将呼叫打到routes.MapMvcAttributeRoutes()的默认路由之前。




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个可选参数,并且该参数必须是最右边的参数。这里的第二条路由是无法访问的执行路径,因为所有三个第一个参数都是可选的。

[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属性可以单独提供的灵活。

另外,如果这些URL面向Internet(不在登录后),则这不是SEO友好的方法。搜索引擎放置在URL中使用公司,分支机构,部门和子部门名称会更好。

无论您是否决定坚持使用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;

关于c# - 属性路由显示为查询字符串,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/32579882/

10-12 00:05
查看更多