ASP.NET маршрутизация - предотвращение столкновений между контроллером / действием и тщеславием / ссылками на URL - PullRequest
2 голосов
/ 28 сентября 2010

Я ищу хорошее решение для использования схемы URL, которая работает как для стандартных ASP.NET MVC-контроллеров / URL-адресов действий, например:

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

, так и для URL-адресов vanity / slug, например:

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

Важно отметить, что я хочу, чтобы генерация исходящих URL работала так, чтобы

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

выдавал / fred / post - not / Posts / View / fred / post

КажетсяЯ могу заставить его работать для входящей или исходящей маршрутизации, но не для обоих.Или я могу заставить это работать, но это грязно и может сломаться.Какие есть подходы, советы и хитрости для того, чтобы что-то вроде этого работало чисто?

1 Ответ

2 голосов
/ 28 сентября 2010

Я наконец-то нашел решение использовать ограничение маршрутизации, которое может проверить, соответствует ли параметр (или не совпадает) имени контроллера:

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, чтобы ограничение проверяло, что параметр соответствует имени контроллера.

...