Asp.net mvc 3 路线操纵员vs控制器工厂
刚接触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处理路由?感谢您的帮助,这是第一个项目,所以我不确定最好的路线是什么;)没有双关语的意思 更新: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.
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
);