Asp.net mvc 3 路线操纵员vs控制器工厂

Asp.net mvc 3 路线操纵员vs控制器工厂,asp.net-mvc-3,Asp.net Mvc 3,刚接触asp.NETMVC(使用v3+razor),我想知道如何最好地解决基于数据库创建动态路由的问题。基本上,主站点导航将被输入到数据库中,我想将它们作为路由加载。i、 e.-从数据库加载类别列表,然后尽可能将路由附加到路由引擎 mysite.com/cars mysite.com/televisions mysite.com/computers 等等 斜杠后面的每个类别都来自数据库,但是,有一些常规条目,如/about和/contactus,它们将不在数据库中,而是静态地输入到global.

刚接触asp.NETMVC(使用v3+razor),我想知道如何最好地解决基于数据库创建动态路由的问题。基本上,主站点导航将被输入到数据库中,我想将它们作为路由加载。i、 e.-从数据库加载类别列表,然后尽可能将路由附加到路由引擎

mysite.com/cars mysite.com/televisions mysite.com/computers

等等

斜杠后面的每个类别都来自数据库,但是,有一些常规条目,如/about和/contactus,它们将不在数据库中,而是静态地输入到global.asax。。。我的问题是:

对于动态数据库URL,我应该使用自定义RouteHandler或pehaps创建一个ControllerFactory,它将匹配并处理从数据库加载的条目请求。如果我的RouteHandler或CustomControllerFactory在数据库的列表中找不到路由,是否可以让DefaultControllerFactory处理路由?感谢您的帮助,这是第一个项目,所以我不确定最好的路线是什么;)没有双关语的意思

更新:

public ActionResult List(string category)
{
    var products = _repo.Get(category); // however you are getting your data
    return View(products);
}
尝试使用从数据库提取的路由约束,但它现在与默认路由冲突。。。以下是我的自定义约束和管线:

public class CategoryListConstraint : IRouteConstraint
{
    public CategoryListConstraint()
    {
        var repo = new Repository<Topic>();
        var cats = repo.All();
        var values = new List<string>();
        foreach (var c in cats)
        {
            values.Add(c.URI.Replace("/", "").Replace("?", ""));
        }
        this._values = values.ToArray<string>();
    }

    private string[] _values;

    public bool Match(HttpContextBase httpContext,
      Route route,
      string parameterName,
      RouteValueDictionary values,
      RouteDirection routeDirection)
    {
        // Get the value called "parameterName" from the 
        // RouteValueDictionary called "value"
        string value = values[parameterName].ToString();

        // Return true is the list of allowed values contains 
        // this value.
        return _values.Contains(value);
    }
}

主页www.mysite.com使用默认路径加载。所有与约束列表匹配的URL都由类别路由加载。。。但是,如果我有www.mysite.com/admin或www.mysite.com/aboutus,则这些将由类别路由获取,即使约束列表中的值是而不是。困惑…

像这样的东西怎么样

类别控制器:

public ActionResult List(string category)
{
    var products = _repo.Get(category); // however you are getting your data
    return View(products);
}
路线

routers.MapRoute(
    "About",
    "About",
    new { controller = "Home", action = "About" });

//... other static routes

routes.MapRoute(
    "CategoriesList",
    "{id}",
    new { controller = "Categories", action = "List" },
    new { id = @"\w+" });
将针对每个路由规则测试传入URL,以查看其是否匹配-如果路由规则匹配,则该规则(及其关联的RouteHandler)就是用于处理请求的规则(并且忽略所有后续规则)。这意味着您通常希望按照“最特定到最不特定”的顺序来构造路由规则


找到了我想要的确切解决方案。代码如下。通过扩展RouteBase类,我成功地避免了使用控制器工厂或实现自定义IRouteHandler,RouteBase类工作得很好,允许我将控制权向下传递到默认的mvc路由,但没有达到特定的要求。顺便说一句-由于中断了与默认路由相关联的控制器,约束最终无法正常工作(尽管默认路由被命中)


嘿,大卫,谢谢你的回复!该解决方案可能有效,但唯一的问题是项目要求URL中不包含“Category”一词。。。。DB(顶级类别)中的列表应视为路由的根。。。或者等等,现在我重读了你的帖子,看起来好像只传递了id。。。最后一个参数是做什么的?刚刚实现了它,它似乎与{controller}/{action}/{id}的默认路由冲突。。。。我需要去掉该路由吗?最后一个参数是一个路由约束,它只匹配字母和数字。如果将默认路由放在最后,则不会导致冲突。唯一要注意的是确保常规控制器与数据库中的任何名称都不匹配,但在我的情况下,这几乎是不可能的;)
public class CustomRoutingEngine : RouteBase 
{
    public override RouteData GetRouteData(HttpContextBase httpContext)
    {                       
        var routeHandler = new MvcRouteHandler();
        var currentRoute = new Route("{controller}/{*URI}", routeHandler);
        var routeData = new RouteData(currentRoute, routeHandler);

        // implement caching here
        var list = GetConstraintList();

        // set your values dynamically here
        routeData.Values["controller"] = "Category";
        // or
        routeData.Values.Add("action", "List");

        // return the route, or null to have it passed to the next routing engine in the list
        var url = Util.StripSlashOnFrontAndBack(httpContext.Request.Path.ToLower()).Split('/')[0];
        if (list.Contains(url))
            return routeData;
        return null;  // have another route handle the routing
    }


    protected List<string> GetConstraintList()
    {
        using (var repo = new RavenRepository<Topic>())
        {
            var tops = repo.Query().Where(x => x.Hidden == false).ToList()
                .Select(x=>x.Name.ToLower());
            List<string> list = new List<string>();
            list.AddRange(tops);
            repo.Dispose();
            return list ?? new List<string>();
        }
    }

    public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
    {
        //implement this to return url's for routes, or null to just pass it on
        return null;
    }
}
            Routes.Clear();

            // Set Defaults
            Routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

            AreaRegistration.RegisterAllAreas();                

            routes.Add(new App.Helpers.CustomRoutingEngine());

            Routes.MapRoute(
                "Default", // Route name
                "{controller}/{action}/{id}", // URL with parameters
                new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
            );