如果我们只输入问题ID,那么SO如何执行URL重写?
questions/{id}/{whatever}
到
questions/{id}/{question-slug}
我已经与MVC工作了一段时间,我让它工作(路线,行动,一切),以便它根据提供的ID选择正确的内容。
但是,{id}
(slug部分)之后的部分保持与输入的相同。因此,如果有人输入content/5/foobar
,它将显示正确的内容,但会离开{{1}在那里。
在控制器中(或其他地方,请建议在哪里)我需要进入数据库并拔出正确的slug,将其放入路径数据中,然后使用此正确的数据执行重定向到相同的操作,我猜?
这是一个使用执行结果覆盖的尝试。它可以工作,但不会在浏览器中重定向或替换/显示正确的URL:
foobar
这是 protected override void Execute(System.Web.Routing.RequestContext requestContext) {
if (requestContext.RouteData.Values["id"] != null) {
string currentSlug = _repository.Find(int.Parse(requestContext.RouteData.Values["id"].ToString())).Slug;
if (requestContext.RouteData.Values["slug"] != null) {
requestContext.RouteData.Values.Remove("slug");
}
requestContext.RouteData.Values.Add("slug", currentSlug);
}
base.Execute(requestContext);
}
动作的另一个非常好用的版本,所以你可以看到它的作用,并了解我的想法:
Display
这个执行永久重定向(它做我想要的)但是它是对的吗? 我想我需要重定向来刷新浏览器URL,不是吗?
答案 0 :(得分:2)
public ActionResult Details(int id, string slug)
{
var session = MvcApplication.CurrentRavenSession;
var blogPostRelations = session
.Query<BlogPost, BlogPosts_WithRelatedData>()
.Where(x => x.IntId == id)
.As<BlogPostRelations>()
.FirstOrDefault()
;
if (blogPostRelations == null)
return HttpNotFound();
if (blogPostRelations.BlogPost.DisplayData.Slug.Value != slug)
return RedirectToActionPermanent("Details", new { id = id, slug = blogPostRelations.BlogPost.DisplayData.Slug.Value });
return View(blogPostRelations);
}
请注意:
if (blogPostRelations.BlogPost.DisplayData.Slug.Value != slug)
return RedirectToActionPermanent("Details", new { id = id, slug = blogPostRelations.BlogPost.DisplayData.Slug.Value });
所以你的#2方法是正确的。
答案 1 :(得分:2)
您可以为此编写自定义路线:
public class QuestionsRoute : Route
{
public QuestionsRoute()
: base(
"questions/{id}/{slug}",
new RouteValueDictionary(new
{
controller = "questions",
action = "index",
slug = UrlParameter.Optional
}),
new RouteValueDictionary(new
{
id = @"\d+"
}),
new MvcRouteHandler()
)
{ }
public override RouteData GetRouteData(HttpContextBase httpContext)
{
var rd = base.GetRouteData(httpContext);
if (rd == null)
{
return null;
}
var id = rd.GetRequiredString("id");
var slug = rd.Values["slug"] as string;
if (string.IsNullOrEmpty(slug))
{
slug = GoFetchSlugFromDb(id);
if (string.IsNullOrEmpty(slug))
{
return null;
}
httpContext.Response.RedirectToRoutePermanent(new
{
action = "index",
controller = "questions",
id = id,
slug = slug
});
return null;
}
return rd;
}
private string GoFetchSlugFromDb(string id)
{
// TODO: you know what to do here
throw new NotImplementedException();
}
}
将在Application_Start
注册:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.Add("questions", new QuestionsRoute());
}
现在你的QuestionsController非常简单:
public class QuestionsController: Controller
{
public ActionResult Index(int id, string slug)
{
...
}
}