URL Rewriting

Bernhard Herzig asked on April 25, 2017 11:54

Hi

I try to achieve following: I want to be able to have a second path prefix beside of the language i know this isn't a thing that kentico supports out of the box. So i decided to write my own URL Rewritting stuff to support this. But my problem is i have this event URLRewritingEvents.ProcessRewritingResult.Before which is mentioned here. Now my problem is i don't get it on how you would do a rewrite inside of this event. I tried to change the e.Parameters.RelativePath to what i want the url should be but it gets ignored. If i try to use the URLRewriter at this point it generates an endless loop because every time i want to do a rewrite it fires the before event.

The use case for example:

/de/ch/home/

Should be rewritten to

/de/home/?country=5

And i can't/won't use the culture to make a difference between the countries. Because we have multiple countries with the same language for editors it's much easier to only maintain a page in one language for multiple countries otherwise they have to write the same content for example 4 times and makes it harder to maintain consistency.

Correct Answer

Michal Samuhel answered on April 26, 2017 11:56

Rewriting is happening in context of request and processing request data. There are more ways how to retrieve URL anyway. With approach I posted above, you could do:

 var context = CMSHttpContext.Current;

        var curUrl = context.Request.AppRelativeCurrentExecutionFilePath;

        var urlArr = curUrl.Split('/');

Or you could use event arguments:

if (e.Parameters.RelativePath.StartsWith("/forum/"))

Or finally you could use something we use in URLRewriter:

RequestContext.RawURL = request.RawUrl;
            string query = RequestContext.CurrentQueryString;
            string actualExt = Path.GetExtension(relativePath).ToLowerCSafe();
            string originalQuery = query;

As for RequestStatusEnum, this marks status of requests and it has planty of states. Without debug or testing it directly I can not say exactly what effect it will have on language. Rewrite class is very complex due to various reasons and main method has above 500lines of code which creates complex paths that I can not follow easily.

However I would say, that language may be processed as most condition checks are on different statuses, but than again this should be tested as languages add an extra layer of complexity.

0 votesVote for this answer Unmark Correct answer

Recent Answers


Michal Samuhel answered on April 25, 2017 12:19

Hi Bernhard. What version of Kentico are you using? There was a bug fixed in 9.37 hotfix.

In general code for rewriting should look like:

...
// rewrite the path to Home page
var url = URLHelper.PortalTemplatePage + "?" + URLHelper.AliasPathParameterName + "=/Home"; 

context.RewritePath(url);

// set the page info context to Home page which has (in this example) NodeID = 104
DocumentContext.CurrentPageInfo = PageInfoProvider.GetPageInfo(SiteContext.CurrentSiteName, "/Home", "en-US", "/Home", 104, true); 

// it is a final rewrite - do not process any other rewrite rules
e.Parameters.Status = RequestStatusEnum.PathRewritten; 
...
0 votesVote for this answer Mark as a Correct answer

Bernhard Herzig answered on April 25, 2017 12:51

Hi Michal

We're using Kentico 10.

I created a class which has as decorater [assembly: RegisterModule(typeof(URLModule))] this one is working fine as it gets executed. inside of the OnInit method I attached the event like this URLRewritingEvents.ProcessRewritingResult.Before += ProcessRewritingResult_Before;

Your answer would help me if I know, where i get context from because i understand it as i can make every rewrite i want if I call context.RewritePath. But one more question is if i want, that he progress also the language rewrite i just don't write e.Parameters.Status = RequestStatusEnum.PathRewritten; am i right?

0 votesVote for this answer Mark as a Correct answer

Bernhard Herzig answered on April 27, 2017 09:17

Hi Michal

Thank you for your advise. I solved it now by doing it like this and it is working fine:

[assembly: RegisterModule(typeof(URLModule))]
namespace Modules
{
    public class URLModule : Module
    {
        public URLModule() : base("URLModule")
        {
        }

        protected override void OnInit()
        {
            base.OnInit();

            URLRewritingEvents.ProcessRewritingResult.Before += ProcessRewritingResult_Before;

        }

        private void ProcessRewritingResult_Before(object sender, URLRewritingEventArgs e)
        {
            if (e.Parameters.ViewMode == CMS.PortalEngine.ViewModeEnum.LiveSite)
            {
                var countries = DocumentHelper.GetDocuments("Country").Path("/%").Published();
                foreach (var country in countries)
                {
                    var urlPrefix = country.GetStringValue("UrlPrefix", string.Empty);
                    if (!string.IsNullOrEmpty(urlPrefix) && System.Text.RegularExpressions.Regex.IsMatch(e.Parameters.RelativePath, "/.*?/" + urlPrefix + "/.*"))
                    {

                        var newPath = e.Parameters.RelativePath.Replace("/" + urlPrefix + "/", "/");
                        var pathWithoutLanguage = newPath.Replace("/" + LocalizationContext.CurrentCulture.CultureAlias + "/", "/");
                        var lastSlash = pathWithoutLanguage.LastIndexOf('/');
                        pathWithoutLanguage = (lastSlash > -1) ? pathWithoutLanguage.Substring(0, lastSlash) : pathWithoutLanguage;

                        var documentContext = DocumentHelper.GetDocuments().Published().Culture(LocalizationContext.CurrentCulture.CultureCode).WhereLike("DocumentNamePath", pathWithoutLanguage).FirstObject;                        
                        if (documentContext != null)
                        {
                            var context = CMSHttpContext.Current;
                            context.RewritePath(newPath);
                            DocumentContext.CurrentPageInfo = PageInfoProvider.GetPageInfo(SiteContext.CurrentSiteName, documentContext.NodeAliasPath, LocalizationContext.CurrentCulture.CultureCode, documentContext.DocumentUrlPath, documentContext.NodeID, false);
                            e.Parameters.Status = RequestStatusEnum.PathRewritten;
                            break;
                        }
                    }
                }
            }
        }
    }
}
0 votesVote for this answer Mark as a Correct answer

   Please, sign in to be able to submit a new answer.