This page has a route hijack currently and a custom render model view to add some extra items to the Razor view which it is grabbing from some other places in Umbraco.
I am wondering if to do a native IIS < rewrite > in the web.config or to use Umbraco ContentFinders. What do you think would be the best approach?
I'm assuming it's a recent v7 install so if I'm way off mark, my apologies.
These are all virtual nodes tied to a single parent node yeah?
Then neither.. Personally I would establish a custom route and use an implementation of UmbracoVirtualNodeRouteHandler to find my content.
This gives you distinct advantage of being able to use Url.Action() in your views to provide consistent navigation links. You'll be also thankful of that when it comes to rendering an XML sitemap.
If you haven't used UmbracoVirtualNodeRouteHandler before, it's ace. Basically you can do the following..
In your ApplicationEventHandler implementation:
protected override void ApplicationStarted(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
{
RouteTable.Routes.MapUmbracoRoute(
"AskQuestionPage",
"Ask-Question/{id}/",
new
{
controller = "QuestionPage",
action = "AskQuestionPage"
},
new AskQuestionVirtualNodeRouteHandler(),
new { id = @"(\d)+" });
}
In your UmbracoVirtualNodeRouteHandler implementation:
public class AskQuestionVirtualNodeRouteHandler : UmbracoVirtualNodeRouteHandler
{
protected override IPublishedContent FindContent(RequestContext requestContext, UmbracoContext umbracoContext)
{
UmbracoHelper helper = new UmbracoHelper(umbracoContext);
string alias = "QuestionPage"; // This could be derived from a strong typed model.
string templateAlias = "AskQuestionPage";
return helper.TypedContentAtRoot()
.First() // Home.
.Descendants()
.First(d => d.DocumentTypeAlias.InvariantEquals(alias)
&& d.GetTemplateAlias().InvariantEquals(templateAlias));
}
}
In your controller.
public class QuestionPageController : RenderMvcController
{
public ActionResult AskQuestionPage(RenderModel model, int id)
{
// Route hijack as normal.
// The RenderModel will be the node that you identified in your implementation.
}
}
I find this pattern allows me to think much more in a pure MVC format wchich provides me with the deep linking functionality that I want.
Because with IIS rewriting you lose the ability to standardise your navigation links. Generally I'd agree that less is better but in this instance the benefit of being able to use upgradable redirects and action links far outweighs the time spent writing the initial code.
In order to support URL's like site.com/en-us/contact-us, I have historically used a rewrite rule in UrlRewriting.config. However, I have found that on Umbraco 7.4.1, I could not for the life of me get my 500 error page working, as it seems HttpContext.Current.Server.TransferRequest("~/unhandled-error") would not hit my route (that returns a static HTML file). Once I converted to a content finder, I was then able to get TransferRequest working. If you are curious, here is my content finder implementation:
// Namespaces.
using System.Text.RegularExpressions;
using Umbraco.Core;
using Umbraco.Core.Models;
using Umbraco.Web.Routing;
/// <summary>
/// Provides an implementation of <see cref="IContentFinder"/> that handles international URL's.
/// </summary>
/// <remarks>
/// <para>
/// Handles <c>/en-us/foo/bar</c> where <c>/foo/bar</c> is the nice url of a document
/// and <c>en-us</c> is the language.
/// </para>
/// <para>
/// This is based on: https://github.com/umbraco/Umbraco-CMS/blob/d50e49ad37fd5ca7bad2fd6e8fc994f3408ae70c/src/Umbraco.Web/Routing/ContentFinderByNiceUrl.cs
/// </para>
/// </remarks>
public class InternationalContentFinder : IContentFinder
{
#region Variables
private static Regex InternationalUrlRegex = new Regex(@"^/?[a-z]{2}-[a-z]{2}(?=$|/|\?)", RegexOptions.Compiled | RegexOptions.IgnoreCase);
#endregion
#region Methods
/// <summary>
/// Tries to find and assign an Umbraco document to a <c>PublishedContentRequest</c>.
/// </summary>
/// <param name="docRequest">The <c>PublishedContentRequest</c>.</param>
/// <returns>A value indicating whether an Umbraco document was found and assigned.</returns>
public virtual bool TryFindContent(PublishedContentRequest docRequest)
{
var route = default(string);
if (docRequest.HasDomain)
{
var rootId = docRequest.UmbracoDomain.RootContentId.Value.ToString();
var path = TrimLanguage(docRequest.Uri.GetAbsolutePathDecoded());
var domain = docRequest.DomainUri;
route = rootId + DomainHelper.PathRelativeToDomain(domain, path);
}
else
{
route = TrimLanguage(docRequest.Uri.GetAbsolutePathDecoded());
}
var node = FindContent(docRequest, route);
return node != null;
}
/// <summary>
/// Removes the language from the beginning of the URL.
/// </summary>
/// <param name="url">
/// The URL.
/// </param>
/// <returns>
/// The URL without the language.
/// </returns>
private string TrimLanguage(string url)
{
if (InternationalUrlRegex.IsMatch(url))
{
var newUrl = InternationalUrlRegex.Replace(url, string.Empty);
if (string.IsNullOrWhiteSpace(newUrl))
{
newUrl = "/";
}
else if (url.StartsWith("?"))
{
newUrl = "/" + newUrl;
}
return newUrl;
}
else
{
return url;
}
}
/// <summary>
/// Tries to find an Umbraco document for a <c>PublishedContentRequest</c> and a route.
/// </summary>
/// <param name="docreq">The document request.</param>
/// <param name="route">The route.</param>
/// <returns>The document node, or null.</returns>
protected IPublishedContent FindContent(PublishedContentRequest docreq, string route)
{
var node = docreq.RoutingContext.UmbracoContext.ContentCache.GetByRoute(route);
if (node != null)
{
docreq.PublishedContent = node;
}
return node;
}
#endregion
}
IIS Rewrite or ContentFinder & UrlSegments?
Hello all
I am building an application for a client where user generated/submitted questions stored in a custom DB table which have their own IDs.
Each item needs a unique URL for deep linking so that it can be shared on sites like FaceBook & Twitter.
The format of the URL needs to be in the following, where 1234 is the unique ID to the posted question
http://site.co.uk/ask-question/1234
This page has a route hijack currently and a custom render model view to add some extra items to the Razor view which it is grabbing from some other places in Umbraco.
I am wondering if to do a native IIS < rewrite > in the web.config or to use Umbraco ContentFinders. What do you think would be the best approach?
Thanks,
Warren
I'm assuming it's a recent v7 install so if I'm way off mark, my apologies.
These are all virtual nodes tied to a single parent node yeah?
Then neither.. Personally I would establish a custom route and use an implementation of
UmbracoVirtualNodeRouteHandler
to find my content.This gives you distinct advantage of being able to use
Url.Action()
in your views to provide consistent navigation links. You'll be also thankful of that when it comes to rendering an XML sitemap.If you haven't used
UmbracoVirtualNodeRouteHandler
before, it's ace. Basically you can do the following..In your
ApplicationEventHandler
implementation:In your
UmbracoVirtualNodeRouteHandler
implementation:In your controller.
I find this pattern allows me to think much more in a pure MVC format wchich provides me with the deep linking functionality that I want.
Hopefully this is useful.
If a simple IIS rewriting rule can handle it... why make it more complicated?
The less code there is, the better.
Because with IIS rewriting you lose the ability to standardise your navigation links. Generally I'd agree that less is better but in this instance the benefit of being able to use upgradable redirects and action links far outweighs the time spent writing the initial code.
What did you use Warren ?
In order to support URL's like
site.com/en-us/contact-us
, I have historically used a rewrite rule inUrlRewriting.config
. However, I have found that on Umbraco 7.4.1, I could not for the life of me get my 500 error page working, as it seemsHttpContext.Current.Server.TransferRequest("~/unhandled-error")
would not hit my route (that returns a static HTML file). Once I converted to a content finder, I was then able to getTransferRequest
working. If you are curious, here is my content finder implementation:is working on a reply...
This forum is in read-only mode while we transition to the new forum.
You can continue this topic on the new forum by tapping the "Continue discussion" link below.