fbpx

Our Black Friday Sale has been extended!  View Sale

ASP.Net MVC: Excluding unwanted query string values from Url.RouteUrl and Url.Action

Overlapping colored triangles

In MVC's generation of outgoing URLs, I thought that the Bind attribute would be useful to leave out route values that are unbound. It turns out that this is not the case, so I was getting URL parameters that represent ViewModel properties that I didn't need to pass around:
http://example.com/?Sizes=System.String[]
Now, I could use fields instead of properties, but that seems unnecessarily restrictive. Extension methods to the rescue! In the following, onlyBoundValues tells the UrlHelper to only include bound values as specified by Include, Exlcude, or both.

/// <summary>
/// Add extension methods that construct outgoing URL's but leave out
/// route values that are excluded by the Bind attribute's Include or
/// Exclude.  The methods to mirror are those that take an object as
///  an argument:
///
/// public string Action(string actionName, object routeValues);
/// public string Action(string actionName, string controllerName
///                    , object routeValues);
/// public string Action(string actionName, string controllerName
///                    , object routeValues, string protocol);
///
/// public string RouteUrl(object routeValues);
/// public string RouteUrl(string routeName, object routeValues);
/// public string RouteUrl(string routeName, object routeValues
///                      , string protocol);
/// </summary>
public static class UrlHelperExtensions
{
    public static string Action(this UrlHelper helper, string actionName
                            , object routeValues, bool onlyBoundValues)
    {
        RouteValueDictionary finalRouteValues =
            new RouteValueDictionary(routeValues);
        if (onlyBoundValues)
        {
            RemoveUnboundValues(finalRouteValues, routeValues);
        }
        // Internally, MVC calls an overload of GenerateUrl with
        // hard-coded defaults.  Since we shouldn't know what these
        // defaults are, we call the non-extension equivalents.
        return helper.Action(actionName, routeValues);
    }
    public static string Action(this UrlHelper helper, string actionName
                            , string controllerName, object routeValues
                            , bool onlyBoundValues)
    {
        RouteValueDictionary finalRouteValues =
            new RouteValueDictionary(routeValues);
        if (onlyBoundValues)
        {
            RemoveUnboundValues(finalRouteValues, routeValues);
        }
        return helper.Action(actionName, controllerName, finalRouteValues);
    }
    public static string Action(this UrlHelper helper, string actionName
                            , string controllerName, object routeValues
                            , string protocol, bool onlyBoundValues)
    {
        RouteValueDictionary finalRouteValues =
            new RouteValueDictionary(routeValues);
        if (onlyBoundValues)
        {
            RemoveUnboundValues(finalRouteValues, routeValues);
        }
        return helper.Action(actionName, controllerName
                         , finalRouteValues, protocol);
    }
    public static string RouteUrl(this UrlHelper helper, object routeValues
                              , bool onlyBoundValues)
    {
        RouteValueDictionary finalRouteValues =
            new RouteValueDictionary(routeValues);
        if (onlyBoundValues)
        {
            RemoveUnboundValues(finalRouteValues, routeValues);
        }
        return helper.RouteUrl(finalRouteValues);
    }
    public static string RouteUrl(this UrlHelper helper, string routeName
                              , object routeValues, bool onlyBoundValues)
    {
        RouteValueDictionary finalRouteValues =
            new RouteValueDictionary(routeValues);
        if (onlyBoundValues)
        {
            RemoveUnboundValues(finalRouteValues, routeValues);
        }
        return helper.RouteUrl(routeName, finalRouteValues);
    }
    public static string RouteUrl(this UrlHelper helper, string routeName
                              , object routeValues, string protocol
                              , bool onlyBoundValues)
    {
        RouteValueDictionary finalRouteValues =
            new RouteValueDictionary(routeValues);
        if (onlyBoundValues)
        {
            RemoveUnboundValues(finalRouteValues, routeValues);
        }
        return helper.RouteUrl(routeName, finalRouteValues, protocol);
    }
    /// <summary>
    /// Reflect into the routeValueObject and remove any keys from
    /// routeValues that are not bound by the Bind attribute
    /// </summary>
    private static void RemoveUnboundValues(RouteValueDictionary routeValues
                                        , object source)
    {
        if (source == null)
        {
            return;
        }
        var type = source.GetType();
        BindAttribute b = null;
        foreach (var attribute in type.GetCustomAttributes(true))
        {
            if (attribute is BindAttribute)
            {
                b = (BindAttribute)attribute;
                break;
            }
        }
        if (b == null)
        {
            return;
        }
        foreach (var property in type.GetProperties())
        {
            var propertyName = property.Name;
            if (!b.IsPropertyAllowed(propertyName))
            {
                routeValues.Remove(propertyName);
            }
        }
    }
}

About the Author:

Visionfriendly.com

Visionfriendly.com

VisionFriendly.com is a Chicago digital marketing agency with over 25 years of experience helping clients nationwide. We have an in-house team of marketers and creatives ready to improve your business’s marketing operations.

Share On:

Comments:

Leave a Comment

Your email address will not be published. Required fields are marked *

Copyright © 2023, All Rights Reserved
Tri Colored Triangles
Scroll to Top

Take your business to the

Next Level!

Visionfriendly.com has the right team to make your business stand out from other professional websites.

Ready For Takeoff?

A Completely Customized
Digital Marketing Experience

  • We'll be in touch within one business day to discuss your goals and create a personalized plan that fits both you and your business.

  • This field is for validation purposes and should be left unchanged.

Let’s start a Conversation