asp.net mvc的新手(使用v3 + razor),我想知道如何最好地解决基于数据库创建动态路由的问题。基本上,主站点导航将输入到数据库中,我想将它们作为路径加载。 ie - 从数据库加载类别列表,然后在可能的情况下将路由附加到路由引擎......
mysite.com/cars mysite.com/televisions mysite.com/computers
等...
斜杠之后的每个类别都来自db,但是,有一些常规条目,比如/ about和/ contactus,它们不会在数据库中,并且已经静态输入到global.asax中...我的问题是:< / p>
对于动态数据库URL,我应该使用自定义RouteHandler或pehaps创建一个ControllerFactory,它将匹配并处理从数据库加载的条目的请求。如果我的RouteHandler或CustomControllerFactory没有从数据库中找到列表中的路由,是否可以让DefaultControllerFactory处理路由?感谢您提供任何帮助,这是第一个项目,所以我不确定最佳路线是什么;)没有双关语......
更新
尝试使用从数据库中提取的路由约束,但它现在与默认路由冲突...这是我的自定义约束和路由:
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);
}
}
以下是路线:
Routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Categories",
"{category}/{*values}",
new { controller = "Category", action = "List" },
new CategoryListConstraint()
);
Routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
主页www.mysite.com使用默认路线加载。匹配约束列表的所有URL都按类别路由加载...但如果我有www.mysite.com/admin或www.mysite.com/aboutus,即使这些值被类别路由选中在约束列表中不。困惑...
答案 0 :(得分:1)
这样的事情怎么样?
类别控制器:
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+" });
针对每个Route规则测试传入的URL以查看它是否匹配 - 如果Route规则匹配,则该规则(及其关联的RouteHandler)是用于处理请求的规则(并忽略所有后续规则) )。这意味着您通常希望以“最具体到最不具体”的顺序构建路由规则
答案 1 :(得分:1)
找到我正在寻找的确切解决方案。代码如下。我设法避免使用Controller Factories或通过使用扩展RouteBase类来实现自定义IRouteHandler,该类工作得很好并且允许我将控制权传递给默认的mvc路由是特定的东西没有被击中。 BTW - 由于打破了与默认路由关联的控制器(尽管默认路由被击中),但约束最终无法正常工作
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
);