ASP.NET 路由 - 避免控制器/操作和虚荣/slug url 之间的冲突

发布于 2024-09-25 00:44:15 字数 546 浏览 3 评论 0原文

我正在寻找一个很好的解决方案,让 URL 方案既适用于标准 ASP.NET MVC 控制器/操作 url,例如:

/Home/About --> Controller "Home", Action "About"

也适用于虚荣/slug url,例如:

/fred/post  --> Controller "Posts", Action "View", User "fred", Post "post"

重要的是,我希望出站 url 生成能够工作,以便

Html.ActionLink("View", "Posts", new { User="fred", Post="post" }, null }

提供 /fred /post - 不是 /Posts/View/fred/post

看来,我可以让它适用于入站或出站路由,但不能同时适用于两者。或者我可以让它工作,但它很混乱并且容易损坏。有什么方法、技巧和窍门可以让这样的事情干净利落地工作?

I'm looking for a good solution to having a URL scheme that works for both standard ASP.NET MVC controller/action urls eg:

/Home/About --> Controller "Home", Action "About"

and vanity/slug urls eg:

/fred/post  --> Controller "Posts", Action "View", User "fred", Post "post"

Importantly, I want the outbound url generation to work so that

Html.ActionLink("View", "Posts", new { User="fred", Post="post" }, null }

gives /fred/post - not /Posts/View/fred/post

It seems, I can get it to work for either inbound or outbound routing but not both. Or I can get it sort of working but it's messy and prone to breaking. What approaches, tips and tricks are there to getting something like this working cleanly?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

烟雨扶苏 2024-10-02 00:44:15

我最终想出了使用路由约束的解决方案,该约束可以检查参数是否与控制器的名称匹配(或不匹配):

public class ControllerConstraint : IRouteConstraint
{
    static List<string> ControllerNames = (from t in System.Reflection.Assembly.GetExecutingAssembly().GetTypes()
                                           where typeof(IController).IsAssignableFrom(t) && t.Name.EndsWith("Controller")
                                           select t.Name.Substring(0, t.Name.Length - 10).ToLower()).ToList();

    bool m_bIsController;
    public ControllerConstraint(bool IsController)
    {

        m_bIsController = IsController;
    }

    public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
    {
        if (m_bIsController)
            return ControllerNames.Contains(values[parameterName].ToString().ToLower());
        else
            return !ControllerNames.Contains(values[parameterName].ToString().ToLower());
    }  
}

像这样使用:

// eg: /myusername
routes.MapRoute(
    "MemberUrl",
    "{member_urlid}",
    new { controller = "Members", action = "View" },
    new { action="View", member_urlid = new ControllerConstraint(false) }
);

// eg: /myusername/mypagename
routes.MapRoute(
    "ItemUrl",
    "{member_urlid}/{item_urlid}",
    new { controller = "Items", action = "View" },
    new { action="View", member_urlid = new ControllerConstraint(false) }
);

// Normal controller/action routes follow

约束 new ControllerConstraint(false)表示如果参数与控制器名称匹配,则不匹配此路由规则。传递 true 以使约束检查参数是否与控制器名称匹配。

I finally came up with the solution of using a routing constraint that can check if a parameter matches (or doesn't match) the name of a controller:

public class ControllerConstraint : IRouteConstraint
{
    static List<string> ControllerNames = (from t in System.Reflection.Assembly.GetExecutingAssembly().GetTypes()
                                           where typeof(IController).IsAssignableFrom(t) && t.Name.EndsWith("Controller")
                                           select t.Name.Substring(0, t.Name.Length - 10).ToLower()).ToList();

    bool m_bIsController;
    public ControllerConstraint(bool IsController)
    {

        m_bIsController = IsController;
    }

    public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
    {
        if (m_bIsController)
            return ControllerNames.Contains(values[parameterName].ToString().ToLower());
        else
            return !ControllerNames.Contains(values[parameterName].ToString().ToLower());
    }  
}

Use like this:

// eg: /myusername
routes.MapRoute(
    "MemberUrl",
    "{member_urlid}",
    new { controller = "Members", action = "View" },
    new { action="View", member_urlid = new ControllerConstraint(false) }
);

// eg: /myusername/mypagename
routes.MapRoute(
    "ItemUrl",
    "{member_urlid}/{item_urlid}",
    new { controller = "Items", action = "View" },
    new { action="View", member_urlid = new ControllerConstraint(false) }
);

// Normal controller/action routes follow

The constraint new ControllerConstraint(false) means don't match this routing rule if the parameter matches the name of a controller. Pass true to make the constraint check that the parameter does match a controller name.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文