Перезапись URL-адреса stackoverflow - PullRequest
3 голосов
/ 21 марта 2012

Как SO выполняет перезапись URL, если мы добавляем только идентификатор вопроса?

questions/{id}/{whatever}

до

questions/{id}/{question-slug}

Я работаю некоторое время с MVC и япусть он работает (маршруты, действия, все), чтобы он подбирал правильное содержимое на основе предоставленного идентификатора.

Однако часть после {id} (часть слага) остается такой же, как и введенная вПоэтому, если кто-то наберет content/5/foobar, он отобразит правильный контент, но оставит там foobar.

В контроллере (или где-то еще, пожалуйста, предложите, где), мне нужно будет перейти вБД и вытащите правильный слаг, поместите его в данные маршрута и затем выполните перенаправление к тому же действию с этими правильными данными, я думаю?

Это попытка с переопределением результата выполнения.Он работает, но не перенаправляет и не заменяет / не отображает правильный URL в браузере:

    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, так что вы можете увидеть, что он делает, и получитьИдея, что я хочу:

    //
    // GET: {culture}/directory/5/{slug}
    public virtual ActionResult Display(int id, string slug)
    {
        var model = _repository.Find(id);
        if (model != null) {
            if (!model.Slug.Equals(slug, System.StringComparison.OrdinalIgnoreCase)) {
                return RedirectToActionPermanent(pndng.DirectoryEntry.ActionNames.Display, pndng.DirectoryEntry.Name, new { id = model.Id, slug = model.Slug });
            }
            return View(model);
        }
        // no model found
        return InvokeHttp404(HttpContext);
    }

Этот выполняет постоянное перенаправление (он делает то, что я хочу), но верно ли это?Наверное, мне нужен редирект для обновления URL браузера, не так ли?

Ответы [ 2 ]

2 голосов
/ 21 марта 2012

Вы можете написать собственный маршрут для этого:

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());
}

Теперь ваш QuestionController будет довольно простым:

public class QuestionsController: Controller
{
    public ActionResult Index(int id, string slug)
    {
        ...
    }
}
2 голосов
/ 21 марта 2012
  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 является правильным.

...