DNN Forums

Ask questions about your website to get help learning DNN and help resolve issues.

Preserving query string parameters during portal navigation

 10 Replies
 0 Subscribed to this topic
 26 Subscribed to this forum
Sort:
Page 1 of 212 > >>
Author
Messages
Growing Member
Posts: 69
Growing Member

Hello,
I am porting several modules developed in DNN 7 to DNN 9.11.
Former colleagues modified the (sealed) "DotNetNuke.Common.Globals.NavigateURL" class to introduce a collection of parameters to be added and stored in query string.
Is there a smart way to do the same thing with DNN 9, possibly without modifying the DNN code base?

Thanks
Seek

Advanced Member
Posts: 233
Advanced Member
4 Helpful Replier
Helpful Replier
Thanks for being such a helpful replier!
New Poster
New Poster
Congrats on posting!
4 Engaged Reader
Engaged Reader
You are an engaged reader!
Hopefully someone with more experience in the community can better answer, but you want to implement INaviationManager.
I relied heavily on these two threads:
https://dnncommunity.org/...ss-controller-class/
https://dnncommunity.org/...s/navigationmanager/
If you want to see it implemented in the Community Forums module:
https://github.com/DNNCom...ices/UrlNavigator.cs
Advanced Member
Posts: 159
Advanced Member
MVP
MVP
You're an MVP!
If you can provide an example of the sort of customization that was previously done, we could probably give you an alternative fairly easily. I'm imagining that you could move your customized methods out into another class that takes an INavigationManager (and/or wraps Globals.NavigateURL, depending on how its used).
Growing Member
Posts: 69
Growing Member
Posted By Brian Dukes on 7/26/2024 7:02 PM
If you can provide an example of the sort of customization that was previously done, we could probably give you an alternative fairly easily. I'm imagining that you could move your customized methods out into another class that takes an INavigationManager (and/or wraps Globals.NavigateURL, depending on how its used).

Sure, here my code based on old DNN 7.4.2

[CODE]
public static string NavigateURL(int tabID, bool isSuperTab, PortalSettings settings, string controlKey, string language, string pageName, params string[] additionalParameters)
{
    string url = tabID == Null.NullInteger ? ApplicationURL() : ApplicationURL(tabID);
    if (!String.IsNullOrEmpty(controlKey))
    {
        url += "&ctl=" + controlKey;
    }
    
    if (isSuperTab)
    {
        url += "&portalid=" + settings.PortalId;
    }

    /* Introduction of a collection of query string elements to be preserved during portal page navigation.
     * A collection of keys is defined, where each key is the name of a query string parameter. For each navigation request, 
     * this class checks the collection and, for each element, verifies its presence in the query string of the current request; 
     * if the element is found, a corresponding entry in the query string will be inserted in the generated URL.
     * This mechanism allows reproducing the behavior that was present when the information about the current company was part 
     * of the HTTP alias: the "CompanySelector" component will take care of keeping the information updated.
     * If one of the parameters of the current request is a URL, the list of its parameters is merged with the list of the 
     * request parameters. Consequently, the value retrieved from the QueryString property is a comma-separated list of all 
     * the parameter values. In this case, I assume that the parameter representing a URL is always the last in the list 
     * and consider only the value of the first occurrence of the parameter. 
     */
    if (HttpContext.Current != null)
    {
        foreach (string parameterName in QueryStringParametersToBePreserved)
        {
            int indexOfParameter = HttpContext.Current.Request.Url.Query.ToUpper().IndexOf(parameterName.ToUpper());

            /* Must check:
             * - generated URL does not contain the current parameter
             * - the current parameter does not in additional parameters (which must prevail) 
             */
            if (indexOfParameter != -1 &&
                !url.ToUpper().Contains(parameterName.ToUpper() + "=") &&
                (additionalParameters == null || !additionalParameters.Any(p => p != null && p.ToUpper().StartsWith(parameterName.ToUpper() + "="))))
            {
                string substringAfterParameter = HttpContext.Current.Request.Url.Query.Substring(indexOfParameter);
                int indexOfAmpersand = substringAfterParameter.IndexOf("&");
                string nameAndValue;
                if (indexOfAmpersand != -1)
                {
                    nameAndValue = substringAfterParameter.Substring(0, indexOfAmpersand);
                }
                else
                {
                    nameAndValue = substringAfterParameter;
                }

                url += "&" + nameAndValue;
            }
        }
    }

    TabInfo tab = null;

    if (settings != null)
    {
        tab = TabController.Instance.GetTab(tabID, isSuperTab ? Null.NullInteger : settings.PortalId, false);
    }

    //only add language to url if more than one locale is enabled
    if (settings != null && language != null && LocaleController.Instance.GetLocales(settings.PortalId).Count > 1)
    {
        if (settings.ContentLocalizationEnabled)
        {
            if (language == "")
            {
                if (tab != null && !string.IsNullOrEmpty(tab.CultureCode))
                {
                    url += "&language=" + tab.CultureCode;
                }
            }
            else
            {
                url += "&language=" + language;
            }
        }
        else if (settings.EnableUrlLanguage)
        {
            //legacy pre 5.5 behavior
            if (language == "")
            {
                url += "&language=" + Thread.CurrentThread.CurrentCulture.Name;
            }
            else
            {
                url += "&language=" + language;
            }
        }
    }

    /* 
     * I place additional parameters at the end of the generated URL: in some cases, the last parameter passed to this method is a URL; 
     * if this URL itself has parameters, these are mistakenly interpreted as parameters of the generated URL, not of the parameter itself, 
     * causing interpretation errors.
     */
    if (additionalParameters != null)
    {
        url = additionalParameters.Where(parameter => !string.IsNullOrEmpty(parameter)).Aggregate(url, (current, parameter) => current + ("&" + parameter));
    }

    if (Host.UseFriendlyUrls || Config.GetFriendlyUrlProvider() == "advanced")
    {
        if (String.IsNullOrEmpty(pageName))
        {
            pageName = glbDefaultPage;
        }

        url = (settings == null) ? FriendlyUrl(tab, url, pageName) : FriendlyUrl(tab, url, pageName, settings);
    }
    else
    {
        url = ResolveUrl(url);
    }

    return url;
}

[CODE]

 

 

Advanced Member
Posts: 159
Advanced Member
MVP
MVP
You're an MVP!

It looks to me like you should be able to wrap the existing <code>NavigateURL</code> functionality, instead of rewriting it. Something like this:

<code>public class NavigationUtility {
private readonly INavigationManager navigationManager;
public NavigationUtility(INavigationManager navigationManager)
{
    this.navigationManager = navigationManager;
}

public string NavigateURL(int tabID, bool isSuperTab, PortalSettings settings, string controlKey, string language, string pageName, params string&#91;&#93; additionalParameters)
{
    var allParameters = new List<string>(additionalParameters ?? Array.Empty&ltstring>());

    /* Introduction of a collection of query string elements to be preserved during portal page navigation.
     * A collection of keys is defined, where each key is the name of a query string parameter. For each navigation request, 
     * this class checks the collection and, for each element, verifies its presence in the query string of the current request; 
     * if the element is found, a corresponding entry in the query string will be inserted in the generated URL.
     * This mechanism allows reproducing the behavior that was present when the information about the current company was part 
     * of the HTTP alias: the "CompanySelector" component will take care of keeping the information updated.
     * If one of the parameters of the current request is a URL, the list of its parameters is merged with the list of the 
     * request parameters. Consequently, the value retrieved from the QueryString property is a comma-separated list of all 
     * the parameter values. In this case, I assume that the parameter representing a URL is always the last in the list 
     * and consider only the value of the first occurrence of the parameter. 
     */
    if (HttpContext.Current != null)
    {
        foreach (string parameterName in QueryStringParametersToBePreserved)
        {
            int indexOfParameter = HttpContext.Current.Request.Url.Query.ToUpper().IndexOf(parameterName.ToUpper());

            /* Must check: the current parameter does not in additional parameters (which must prevail) */
            if (indexOfParameter != -1 &&
                !additionalParameters.Any(p => p != null && p.ToUpper().StartsWith(parameterName.ToUpper() + "=")))
            {
                string substringAfterParameter = HttpContext.Current.Request.Url.Query.Substring(indexOfParameter);
                int indexOfAmpersand = substringAfterParameter.IndexOf("&");
                string nameAndValue;
                if (indexOfAmpersand != -1)
                {
                    nameAndValue = substringAfterParameter.Substring(0, indexOfAmpersand);
                }
                else
                {
                    nameAndValue = substringAfterParameter;
                }

                allParameters.Add(nameAndValue);
            }
        }
    }

    return this.navigationManager.NavigateURL(tabID, isSuperTab, settings, controlKey, language, pageName, allParameters.ToArray());
}
</code>
Growing Member
Posts: 69
Growing Member

Thanks!
What do you think is better to do?
Inherit the class
Modify the existing DNN code
What else?

Growing Member
Posts: 69
Growing Member
Posted By Seek78 on 7/30/2024 8:55 AM

Thanks!
What do you think is better to do?
Inherit the class
Modify the existing DNN code
What else?

 

I mean, I want it as default for all URL visited in the portal.

 

Advanced Member
Posts: 159
Advanced Member
MVP
MVP
You're an MVP!
To affect all URLs generated, you would need to modify the core code, or create your own friendly URL provider.
Growing Member
Posts: 69
Growing Member
Posted By Brian Dukes on 7/31/2024 3:22 PM
create your own friendly URL provider.

 

Could you provide come examples?
Thanks
S.

 

Advanced Member
Posts: 159
Advanced Member
MVP
MVP
You're an MVP!

Maybe something like this (and then adjust the <code>friendlyUrl</code> section of the <code>web.config</code> to point to your provider):

using System;
using DotNetNuke.Abstractions.Portals;
using DotNetNuke.Common;
using DotNetNuke.Entities.Tabs;
using DotNetNuke.Services.Url.FriendlyUrl;

namespace overridednnurls
{
    public class SpecialFriendlyUrlProvider : FriendlyUrlProvider
    {
        private static readonly string[] QueryStringParametersToBePreserved = { "CompanySelector", };
            
        public override string FriendlyUrl(TabInfo tab, string path)
        {
            return DNNFriendlyUrlProvider.Instance().FriendlyUrl(tab, AdjustParameters(path));
        }

        public override string FriendlyUrl(TabInfo tab, string path, string pageName)
        {
            return DNNFriendlyUrlProvider.Instance().FriendlyUrl(tab, AdjustParameters(path), pageName);
        }

        public override string FriendlyUrl(TabInfo tab, string path, string pageName, string portalAlias)
        {
            return DNNFriendlyUrlProvider.Instance().FriendlyUrl(tab, AdjustParameters(path), pageName, portalAlias);
        }

        public override string FriendlyUrl(TabInfo tab, string path, string pageName, IPortalSettings settings)
        {
            return DNNFriendlyUrlProvider.Instance().FriendlyUrl(tab, AdjustParameters(path), pageName, settings);
        }

        private static string AdjustParameters(string path)
        {
            if (!Uri.TryCreate(path, UriKind.Relative, out var url))
            {
                return path;
            }
            
            /* Introduction of a collection of query string elements to be preserved during portal page navigation.
             * A collection of keys is defined, where each key is the name of a query string parameter. For each navigation request,
             * this class checks the collection and, for each element, verifies its presence in the query string of the current request;
             * if the element is found, a corresponding entry in the query string will be inserted in the generated URL.
             * This mechanism allows reproducing the behavior that was present when the information about the current company was part
             * of the HTTP alias: the "CompanySelector" component will take care of keeping the information updated.
             * If one of the parameters of the current request is a URL, the list of its parameters is merged with the list of the
             * request parameters. Consequently, the value retrieved from the QueryString property is a comma-separated list of all
             * the parameter values. In this case, I assume that the parameter representing a URL is always the last in the list
             * and consider only the value of the first occurrence of the parameter.
             */

            if (HttpContextSource.Current != null)
            {
                foreach (string parameterName in QueryStringParametersToBePreserved)
                {
                    int indexOfParameter = HttpContextSource.Current.Request.Url.Query.IndexOf(parameterName, StringComparison.OrdinalIgnoreCase);
                    if (indexOfParameter != -1 && !path.ToUpperInvariant().Contains(parameterName.ToUpperInvariant() + "="))
                    {
                        string substringAfterParameter = HttpContextSource.Current.Request.Url.Query.Substring(indexOfParameter);
                        int indexOfAmpersand = substringAfterParameter.IndexOf('&');
                        string nameAndValue;
                        if (indexOfAmpersand != -1)
                        {
                            nameAndValue = substringAfterParameter.Substring(0, indexOfAmpersand);
                        }
                        else
                        {
                            nameAndValue = substringAfterParameter;
                        }

                        path += "&" + nameAndValue;
                    }
                }
            }

            return path;
        }
    }
}
Page 1 of 212 > >>

These Forums are for the discussion of the open source CMS DNN platform and ecosystem.

For the benefit of the community and to protect the integrity of the ecosystem, please observe the following posting guidelines:

  1. If you have (suspected) security issues, please DO NOT post them in the forums but instead follow the official DNN security policy
  2. No Advertising. This includes the promotion of commercial and non-commercial products or services which are not directly related to DNN.
  3. No vendor trolling / poaching. If someone posts about a vendor issue, allow the vendor or other customers to respond. Any post that looks like trolling / poaching will be removed.
  4. Discussion or promotion of DNN Platform product releases under a different brand name are strictly prohibited.
  5. No Flaming or Trolling.
  6. No Profanity, Racism, or Prejudice.
  7. Site Moderators have the final word on approving / removing a thread or post or comment.
  8. English language posting only, please.

Would you like to help us?

Awesome! Simply post in the forums using the link below and we'll get you started.

Get Involved