Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • Jeroen Breuer 4908 posts 12265 karma points MVP 4x admin c-trib
    Sep 20, 2010 @ 13:24
    Jeroen Breuer
    0

    URL rewrite for custom data

    Hello,

    I've developed a custom section in which webshop products can be managed. These products are stored in custom tables I've added to the database. Now I'd like to use url rewrite when these products are viewed in the webshop. What's the best approach for this? Is there an Umbraco tv episode available where I can learn how to do custom url rewrite? I'm using Umbraco 4.5 with ASP.NET 4.0 so I could also use the new url routing features of ASP.NET to do this. I'm currently watching this tekpub video about it.

    Should I use the default umbraco url rewrite or the new ASP.NET 4.0 url routing features to solve this? Thanks.

    Jeroen

  • Stefan Kip 1614 posts 4131 karma points c-trib
    Sep 20, 2010 @ 13:37
    Stefan Kip
    0

    There is another option though; UrlRewrite module for IIS

  • Jeroen Breuer 4908 posts 12265 karma points MVP 4x admin c-trib
    Sep 20, 2010 @ 13:51
    Jeroen Breuer
    0

    Thanks for the tip :). What would you recommand? I'd rather do it without doing something to IIS and just manage it inside the code.

    Jeroen

  • Stefan Kip 1614 posts 4131 karma points c-trib
    Sep 20, 2010 @ 14:04
    Stefan Kip
    0

    Well, if you can, use the UrlRewriting.Net plugin which umbraco uses.

    I say 'if you can', because it doesn't support everything unlike the UrlRewrite module.

    As fas as .NET 4.0 url routing concerns; I don't have experience with it yet ;-)

  • Jeroen Breuer 4908 posts 12265 karma points MVP 4x admin c-trib
    Sep 20, 2010 @ 15:52
    Jeroen Breuer
    0

    Well I got the UrlRewriting.Net plugin from Umbraco working, but I must be doing something wrong because the page get's called constantly. If I debug the page load method the breakpoint get hit's constantly. Here is what I've done:

    Config settings:

    <add name="productDetails"
             virtualUrl="^~/nl/artikelen/detail/(.*)/(.*)/([A-Za-z0-9\-]+)/"
             destinationUrl="~/nl/articles/articledetails?id=$3"/>

    The url I'm calling:

    http://localhost:3748/nl/artikelen/detail/test/itworks/600/

    Somehow it looks like it's in loop. Anyone had this before? Thanks.

    Jeroen

  • Stefan Kip 1614 posts 4131 karma points c-trib
    Sep 20, 2010 @ 15:55
    Stefan Kip
    0

    Use Fiddler to see what happens; is it a infinite loop and if so, what's the response header of the first request?

  • Jeroen Breuer 4908 posts 12265 karma points MVP 4x admin c-trib
    Sep 20, 2010 @ 15:58
    Jeroen Breuer
    0

    Thanks for the tip. Somehow it now works. Didn't change anything, but the page load breakpoint now only get's hit once. If the problem happens again I'll use Fiddler :).

    Jeroen

  • James Telfer 65 posts 165 karma points
    Sep 21, 2010 @ 05:29
    James Telfer
    3

    There's a few things here...

    With respect to the multiple hit problem, have a close look at your regex. You could either use a lazy quantifier (with a different multiplicity) or an exclusion group to restrict the eagerness of the match, and you can also use the end of input marker to make it a little clearer. You can also drop the unnecessary groups. All these things reduce the possibility of an unintended match leading to a redirect loop.

    For example:

    • lose the groups: ^~/nl/artikelen/detail/.*/.*/([A-Za-z0-9\-]+)/

    • lazy quantifier: ^~/nl/artikelen/detail/.+?/.+?/([A-Za-z0-9\-]+)/  (this means that it will not match /nl/artikelen/detail/1/2/3/id/, nor will it match a double slash (//))
    • OR an exclusion: ^~/nl/artikelen/detail/[^/]+/[^/]+/([A-Za-z0-9\-]+)/

    • also, optionally, add the end of line marker: ^~/nl/artikelen/detail/.+?/.+?/([A-Za-z0-9\-]+)/$ (watch out for the interaction with the query string here)
    • and you can make the trailing slash optional: ^~/nl/artikelen/detail/.+?/.+?/([A-Za-z0-9\-]+)/?$

    For the rewriting tool, I'd probably come down on the side of the inbuilt engine, as kipusoep did. It's simple, it gets the job done, and it's there in umbraco independent of your server's configuration. It's also a technique that other devs are more likely to grasp, making your solution easier to maintain.

    The only drawback that I found (and I believe that this may also be the case with the IIS7 rewriter) is that the ASP.NET form element's action attribute uses the URL _after_ rewrite. This means that when you postback, your user starts to see the formerly hidden URL. To get around this, you need to use the ControlAdapter architecture of ASP.NET via the App_Browsers. EF has a full implementation of this, but I'll cherry pick a couple of items:

    1. create a class that overrides the Umbraco form rewriting (extends umbraco.presentation.urlRewriter.UrlRewriterFormWriter):

    public override void WriteAttribute(string name, string value, bool fEncode)
    {
        if (name == "action")
        {
            HttpContext current = HttpContext.Current;
            if (current.Items["ActionAlreadyWritten"] == null)
            {
                string virtualUrl = (string)current.Items["UrlRewritingNet.UrlRewriter.VirtualUrl"];
    
                if (!string.IsNullOrEmpty(virtualUrl))
                {
                    // rewrite taken place, change the form action
                    value = virtualUrl;
    
                    // set the context flag so the umbraco control doesn't overwrite it
                    current.Items["ActionAlreadyWritten"] = true;
                }
            }
        }
    
    2. Create the hook ControlAdapter class that will activate this:
    public class FormRewriteControlAdapter : ControlAdapter
    {
        protected override void Render(HtmlTextWriter writer)
        {
            // this is the class created above
            base.Render(new UrlRewriterFormRewriter(writer));
        }
    }
    
    3. Enable this in the App_Browsers/Form.browser file:
    <browsers>
      <browser refID="Default">
        <controlAdapters>
          <adapter controlType="System.Web.UI.HtmlControls.HtmlForm"
                   adapterType="YourNamespace.FormRewriteControlAdapter" />
        </controlAdapters>
      </browser>
    </browsers>

    I got this technique from a combination of Umbraco forum posts (which I can't remember now) and the ever-trusty Reflector :)

    With regard to ASP.NET routing, I don't know enough about it. However, rewrite will do the job simply and easily, so I'm not sure what this would gain for you.

    As for IIS7 rewrite, I don't think our servers have IIS7, and I'm pretty sure this module isn't available for IIS6. It's pretty good though, and when we eventually upgrade this will be great for us.

    What we do have though is ISAPIRewrite. This is as powerful or more so than the IIS7 rewrite (it's pretty much the Apache mod_rewrite, which rocks) and it's installed on the servers. It's ISAPI, so I'm pretty sure it's outside the processing pipeline which means that you don't have to worry about the form action attribute. However, it limits the portability to other servers as it's an extra dependency. That is, if you need to install it on another host, you'll either need a license or you'll be changing your implementation.

    I hope this helps!

    Regards from down under :)

  • Jeroen Breuer 4908 posts 12265 karma points MVP 4x admin c-trib
    Sep 21, 2010 @ 11:51
    Jeroen Breuer
    0

    Thank you James! Used your example and postbacks now also work :). Glad your my colleague ;).

    Jeroen

  • Stefan Kip 1614 posts 4131 karma points c-trib
    Sep 21, 2010 @ 11:58
  • Jeroen Breuer 4908 posts 12265 karma points MVP 4x admin c-trib
    Oct 12, 2010 @ 09:54
    Jeroen Breuer
    0

    Hello,

    I've been using the umbraco url writing for a while now with succes, but I'd like to adjust the custom url and this goes wrong.

    Currently I've got this in the UrlRewritting.config file:

        <!--NL UrlRewrite-->
        <add name="productOverviewNL"
             virtualUrl="^~/nl/overzicht/([A-Za-z0-9\-]+)/([A-Za-z0-9\-]+)"
             destinationUrl="~/nl/artikelen/artiekel-overzicht?id=$2"/>
    
        <add name="productDetailsNL"
             virtualUrl="^~/nl/details/([A-Za-z0-9\-]+)/([A-Za-z0-9\-]+)/([A-Za-z0-9\-]+)"
             destinationUrl="~/nl/artikelen/artiekel-details?id=$3"/>

    Now I'd like to remove the "overzicht" and "details" part of url so it get's shorter. This gives me 2 problems:

    1 Both pages always redirect to the first url.

    Here is an example:

        <!--NL UrlRewrite-->
        <add name="productOverviewNL"
             virtualUrl="^~/nl/([A-Za-z0-9\-]+)"
             destinationUrl="~/nl/artikelen/artiekel-overzicht?name=$1"/>
    
        <add name="productDetailsNL"
             virtualUrl="^~/nl/([A-Za-z0-9\-]+)/([A-Za-z0-9\-]+)"
             destinationUrl="~/nl/artikelen/artiekel-details?name=$2"/>

    Now if I go to /nl/test1 it redirects me to ~/nl/artikelen/artiekel-overzicht but if I go to /nl/test1/subtest1 it still goes to ~/nl/artikelen/artiekel-overzicht instead of ~/nl/artikelen/artiekel-details.

    What am I doing wrong here? Probably got something to do with the regex I'm using, but I don't know how to solve this.

    2 Other url's also get redirected to these pages.

    For example if I create a news section the url is /nl/news, but because of the url rewritting it still goes to ~/nl/artikelen/artiekel-overzicht. Is there a way to say url's generated from Umbraco shouldn't redirect?

    Hope someone can help me with this :). Thanks.

    Jeroen

  • Stefan Kip 1614 posts 4131 karma points c-trib
    Oct 12, 2010 @ 10:01
    Stefan Kip
    0

    Solution to your first problem:

        
       
    name="productOverviewNL"
             
    virtualUrl="^~/nl/([A-Za-z0-9\-]+)$"
             
    destinationUrl="~/nl/artikelen/artiekel-overzicht?name=$1"/>

    About your second problem; you should really make the URL unique...
    Something like "^~/nl/artikel/([A-Za-z0-9\-]+)$"

  • Jeroen Breuer 4908 posts 12265 karma points MVP 4x admin c-trib
    Oct 12, 2010 @ 10:23
    Jeroen Breuer
    0

    Thanks Stefan you solved my first problem :). As for the second problem I guess I could make it unique though I would have hoped there would be a better solution. At least I'll make them unique by this: "^~/nl/([A-Za-z0-9\-]+)/artikel$" this way the unique part is at the back of the url which is better for SEO.

    Jeroen

  • Stefan Kip 1614 posts 4131 karma points c-trib
    Oct 12, 2010 @ 10:26
    Stefan Kip
    0

    Hmm no, the unique part of the url itself is the '([A-Za-z0-9\-]+)' part, the '/artikel' part is only the unique identifier for you url rewrite.

    You see this on the web all the time, think of blogposts, the unique part at the end like this: /2010/10/12/the-title-of-the-article

  • Jeroen Breuer 4908 posts 12265 karma points MVP 4x admin c-trib
    Oct 12, 2010 @ 11:08
    Jeroen Breuer
    0

    Hi Stefan,

    You're right about the unique part. That's '([A-Za-z0-9\-]+)' and '/artikel' is only so the url rewrite knows which template should be used.

    As for the SEO part here's something our SEO expert wrote:

    "Good SEO or any readable URLs for that matter are usually composed by a simple idea; a breadcrumb path.

    This would translate to the following in some news or blog sites
    /YYYY/MM/DD/Post-title

    And for webshops or other item related websites
    Product view: /Main-category/sub-category/product-title
    Subcategory view: /Main-category/sub-category
    Category view: /Main-category

    As you can see, removing any of the rightmost items will result in a naturally occurring page. 

    However this can be troublesome for sites that have other pages (such as contact etc.) this would force you to use switch statements or other maintenance horrors. Not to mention sites that use multiple languages and multiple templates.

    So one solution would be
    /language-ISO-code/products/main-category/sub-category/product-title

    Or to eliminate template choosing
    /language-ISO-code/products/main-category/sub-category/product-title/template-name

    And finally to make the path even shorter
    /language-ISO-code/main-category/sub-category/product-title/template-name

    So for example:
    /en/elevators/glass/turbo-tube-taker/detail
    And:
    /en/elevators/glass/overview"

    That's why I'm moving the template part to the back of the url.

    Jeroen

  • Jeroen Breuer 4908 posts 12265 karma points MVP 4x admin c-trib
    Oct 12, 2010 @ 17:58
    Jeroen Breuer
    0

    I've got a new small problem. This is my url rewrite now:

    <!--NL UrlRewrite-->
    <add name="productOverviewNL"
          virtualUrl="^~/nl/([A-Za-z0-9\-]+)/overzicht"
          destinationUrl="~/nl/artikelen/artiekel-overzicht?categoryName=$1"/>

    If I go to the url "/nl/tilliften/overzicht/" in the request.querystring I get "tilliften/". Is there something I can do so I don't get the slash?

    Jeroen

  • Stefan Kip 1614 posts 4131 karma points c-trib
    Oct 12, 2010 @ 21:07
    Stefan Kip
    0

    Hmm, that shouldn't happen... I tested it with RegExr and it works as it should.

    Can you try using IIS UrlRewriting add-on? That way you can test if UrlRewriting.NET is buggy (well, IIS UrlRewriting owns UrlRewriting.NET anyway :P )

  • James Telfer 65 posts 165 karma points
    Oct 13, 2010 @ 11:44
    James Telfer
    0

    I agree with @kipusoep, fwiw, that slash doesn't match in that regex. It's has to be a bug or somehow your config was cached incorrectly. It might sound stupid, but have you tried bouncing IIS/windows?

Please Sign in or register to post replies

Write your reply to:

Draft