stackoverflow URL重写

时间:2012-03-21 14:00:39

标签: asp.net-mvc routing asp.net-mvc-routing

如果我们只输入问题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,不是吗?

2 个答案:

答案 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)
    {
        ...
    }
}